首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >尝试从文件和目录创建tar.gz文件时出现“写太长”错误

尝试从文件和目录创建tar.gz文件时出现“写太长”错误
EN

Stack Overflow用户
提问于 2016-07-19 09:41:42
回答 3查看 8.5K关注 0票数 9

因此,我试图从多个目录和文件中缓存一个tar.gz文件文件。与以下事物的用法相同的事物:

代码语言:javascript
运行
复制
tar -cvzf sometarfile.tar.gz somedir/ someotherdir/ somefile.json somefile.xml

假设目录中有其他目录。我把这作为一种投入:

代码语言:javascript
运行
复制
    paths := []string{
      "somedir/",
      "someotherdir/",
      "somefile.json",
      "somefile.xml",
    }

并使用这些方法:

代码语言:javascript
运行
复制
    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
        })
}

问题:如果目录很大,则为

代码语言:javascript
运行
复制
archive/tar: write too long

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

想法用完了,花了很多时间在这个问题上,试图找到解决办法.

有什么想法吗?

谢谢

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-10-12 16:23:01

我也遇到了类似的问题,直到我更仔细地查看了tar.FileInfoHeader文档:

FileInfoHeader从fi创建一个部分填充的标头。如果fi描述符号链接,则FileInfoHeader将链接记录为链接目标。如果fi描述一个目录,则在名称后面追加一个斜杠。因为os.FileInfo的Name方法只返回它描述的文件的基本名称,所以可能需要修改返回头的name字段以提供文件的完整路径名。

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

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

代码语言:javascript
运行
复制
    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
})
票数 12
EN

Stack Overflow用户

发布于 2016-07-19 09:58:09

写入tar存档中的当前条目。如果在ErrWriteTooLong之后写入的hdr.Size字节多于hdr.Size字节,那么Write将返回错误WriteHeader。

有一个Size选项可以添加到标题中。还没试过但也许这有帮助..。

另见https://golang.org/pkg/archive/tar/

票数 0
EN

Stack Overflow用户

发布于 2020-12-03 18:19:59

由于您只在一个大目录中看到这个问题,我认为下面的修复可能没有帮助,但这将解决从可能不断增长的文件中创建tar的问题。

在我的例子中,问题是当我们创建tar头时,header.Size (在tar.FileInfoHeader内部)在那个时刻得到了文件大小(info.Size())的设置。

当我们稍后在代码中打开相关文件(os.Open)并复制其内容(io.Copy)时,我们可能会复制更多的数据,而不是前面将tar标头大小设置为的数据,因为在此期间该文件可能已经增长。

这段代码将确保在将tar标头大小设置为:

代码语言:javascript
运行
复制
_, err = io.**CopyN**(tw, file, info.Size())
if err != nil {
    log.Println("failing here")
    return err
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38454850

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档