go - 尝试从文件和目录创建 tar.gz 文件时出现 `write too long` 错误

标签 go tar gzip

所以我试图从多个目录和文件创建一个 tar.gz 文件。与以下用法相同的东西:

tar -cvzf sometarfile.tar.gz somedir/ someotherdir/ somefile.json somefile.xml

假设目录中有其他目录。 我有这个作为输入:

    paths := []string{
      "somedir/",
      "someotherdir/",
      "somefile.json",
      "somefile.xml",
    }

并使用这些:

    func TarFilesDirs(paths []string, tarFilePath string ) error {
       // set up the output file
       file, err := os.Create(tarFilePath)
       if err != nil {
           return err
       }

       defer file.Close()
       // set up the gzip writer
       gz := gzip.NewWriter(file)
       defer gz.Close()

       tw := tar.NewWriter(gz)
       defer tw.Close()

       // add each file/dir as needed into the current tar archive
       for _,i := range paths {
          if err := tarit(i, tw); err != nil {
               return err
          }
       }

       return nil
   }

func tarit(source string, tw *tar.Writer) error {
    info, err := os.Stat(source)
    if err != nil {
        return nil
    }

    var baseDir string
    if info.IsDir() {
        baseDir = filepath.Base(source)
    }

    return filepath.Walk(source,
        func(path string, info os.FileInfo, err error) error {
            if err != nil {
                return err
            }

            header, err := tar.FileInfoHeader(info, info.Name())
            if err != nil {
                return err
            }

            if baseDir != "" {
                header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, source))
            }

            if err := tw.WriteHeader(header); err != nil {
                return err
            }

            if info.IsDir() {
                return nil
            }

            file, err := os.Open(path)
            if err != nil {
                return err
            }

            defer file.Close()

            _, err = io.Copy(tw, file)
            if err != nil {
                log.Println("failing here")
                return err
            }

            return err
        })
}

问题:如果目录很大,我会得到:

archive/tar: write too long

错误,当我删除它时一切正常。

用完了想法,并为此浪费了很多时间试图找到解决方案......

有什么想法吗?

谢谢

最佳答案

在仔细查看 tar.FileInfoHeader 文档之前,我遇到了类似的问题:

FileInfoHeader creates a partially-populated Header from fi. If fi describes a symlink, FileInfoHeader records link as the link target. If fi describes a directory, a slash is appended to the name. Because os.FileInfo's Name method returns only the base name of the file it describes, it may be necessary to modify the Name field of the returned header to provide the full path name of the file.

本质上,FileInfoHeader 不能保证在您使用 WriteHeader 写入之前填写所有 header 字段,如果您查看实现,Size 字段仅设置在 regular 上。文件。您的代码片段似乎只处理目录,这意味着如果您遇到任何其他非常规文件,您将写入大小为零的 header ,然后尝试将磁盘上可能非零大小的特殊文件复制到 tar 中。 Go 返回 ErrWriteTooLong 以阻止您创建损坏的 tar。

我想到了这个,从那以后就再也没有遇到过这个问题。

    if err := filepath.Walk(directory, func(path string, info os.FileInfo, err error) error {
        if err != nil {
            return check(err)
        }

        var link string
        if info.Mode()&os.ModeSymlink == os.ModeSymlink {
            if link, err = os.Readlink(path); err != nil {
                return check(err)
            }
        }

        header, err := tar.FileInfoHeader(info, link)
        if err != nil {
            return check(err)
        }

        header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, directory))
        if err = tw.WriteHeader(header); err != nil {
            return check(err)
        }

        if !info.Mode().IsRegular() { //nothing more to do for non-regular
            return nil
        }

        fh, err := os.Open(path)
        if err != nil {
            return check(err)
        }
        defer fh.Close()

        if _, err = io.CopyBuffer(tw, fh, buf); err != nil {
            return check(err)
        }
        return nil
})

关于go - 尝试从文件和目录创建 tar.gz 文件时出现 `write too long` 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38454850/

相关文章:

for-loop - for 循环中的 goroutines 问题

asp-classic - 是否可以在经典 ASP 页面上使用 GZIP 压缩?

linux - 在超过十亿个文件的目录执行 "tar"时,进程停留在D状态

Java:创建 GZIPInputStream 时出错:不是 GZIP 格式

http - Varnish 不 gzip html 页面

对结构图进行排序 - GOLANG

google-app-engine - 如何验证 JWT 签名?

http - google.com 的 golang 反向代理

linux - 使用 tar 压缩日志目录,当 apache 尝试在压缩期间写入时会发生什么?

python - 如何将 .tar 转换为 .tgz