使用Golang打包目录

3

我有些困难,不知道如何将目录写入tarball的头信息中。例如,我有以下目录结构:

test [dir]
-- test1.txt
    -- subDirA [sub dir]
         -- test2.txt

如果我使用Go tar可执行文件对test进行打包,那么解压后将保留原有结构。如果在tarball上运行tar -tvf命令,则得到的列表如下:

test/test1.txt 
test/subDirA/test2.txt

然而,如果我手动执行tar -cvf test命令,然后执行tar -tvf命令,列表将会是:

test/
test/test1.txt
test/subDirA/
test/subDirA/test2.txt

这是我希望我的Go打包程序也能做到的。在我的Go程序中,我尝试添加一个新的方法writeDirToTar来处理将目录添加到tarWriter中。我从fileWalk函数中调用writeFileToTar或writeDirToTar。当我在writeDirToTar中调用io.Copy(tarWriter, file)时,我会收到“test/subDirA是一个目录”的错误提示,这有点讲得通。是否有解决方法?
func writeToTar(fileDir string,
        sourceBase string,
        tarWriter *tar.Writer,
        f os.FileInfo) error {

        file, err := os.Open(fileDir)
        if err != nil {
                log.Print("error opening file")
                return err
        }
        defer file.Close()

        // relative paths are used to preserve the directory paths in each file path
        relativePath, err := filepath.Rel(sourceBase, fileDir)

        tarheader := new(tar.Header)
        tarheader.Name = relativePath
        tarheader.Size = f.Size()
        tarheader.Mode = int64(f.Mode())
        tarheader.ModTime = f.ModTime()

        err = tarWriter.WriteHeader(tarheader)
        if err != nil {
                log.Print("error writing tarHeader")
                return err
        }
        _, err = io.Copy(tarWriter, file)
        if err != nil {
                log.Print("error writing to tarWriter")
                return err
        }
        return nil
}

func writeDirToTar(fileDir string,
        sourceBase string,
        tarWriter *tar.Writer,
        f os.FileInfo) error {

        file, err := os.Open(fileDir)
        if err != nil {
                log.Print("error opening file")
                return err
        }
        defer file.Close()

        // relative paths are used to preserve the directory paths in each file path
        relativePath, err := filepath.Rel(sourceBase, fileDir)

        if tarHeader, err := tar.FileInfoHeader(f, relativePath); err != nil {
                log.Print("error writing tarHeader")
                return err
        }

        tarHeader.Name = relativePath
        tarheader.Mode = int64(f.Mode())
        tarheader.ModTime = f.ModTime()

        _, err = io.Copy(tarWriter, file)
        if err != nil {
                log.Print("error writing to tarWriter")
                return err
        }
        return nil

}
1个回答

2
你在tar.Header中缺少Typeflag字段。
对于目录,至少需要:

tarheader := &tar.Header{
    Name:     relativePath,
    Mode:     int64(f.Mode()),
    ModTime:  f.ModTime(),
    Typeflag: tar.TypeDir,
}

你不需要在这里指定大小,也不需要复制目录数据,因为tar对内部目录数据结构没有意义。
您还可以在文件名后添加/以视觉上表示它是一个目录,并匹配POSIX tar行为。
或者,您可以像处理文件一样使用tar.FileInfoHeader函数来创建正确的头结构。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接