代码之家  ›  专栏  ›  技术社区  ›  user4211028

从Go中的tar文件提取

  •  0
  • user4211028  · 技术社区  · 9 年前

    此代码尝试将一些文本tar到 tar 将其归档并解压缩。 的代码 焦油 工作,但似乎我做错了什么 因为 untar 相同的文件不起作用。

    当我解开手动tar的文件时。gz与操作系统GUI,它工作,但 不在此代码中。

    http://play.golang.org/p/diTOojUuBX

    func main() {
            mpath := "a.tar.gz"
            // defer os.Remove(mpath)
            f, err := overwrite(mpath)
            defer f.Close()
            if err != nil {
                    panic(err)
            }
            gw := gzip.NewWriter(f)
            defer gw.Close()
            if err != nil {
                    panic(err)
            }
            tw := tar.NewWriter(gw)
            for _, file := range files {
                    hdr := &tar.Header{
                            Name: file.Name,
                            Mode: 0600,
                            Size: int64(len(file.Body)),
                    }
                    if err := tw.WriteHeader(hdr); err != nil {
                            panic(err)
                    }
                    if _, err := tw.Write([]byte(file.Body)); err != nil {
                            panic(err)
                    }
            }
            // Make sure to check the error on Close.
            if err := tw.Close(); err != nil {
                    panic(err)
            }
    
            fr, err := read(mpath)
            defer fr.Close()
            if err != nil {
                    panic(err)
            }
            gr, err := gzip.NewReader(fr)
            defer gr.Close()
            if err != nil {
                    panic(err)
            }
            tr := tar.NewReader(gr)
            for {
                    hdr, err := tr.Next()
                    if err == io.EOF {
                            // end of tar archive
                            break
                    }
                    if err != nil {
                            panic(err)
                    }
                    path := hdr.Name
                    switch hdr.Typeflag {
                    case tar.TypeDir:
                            if err := os.MkdirAll(path, os.FileMode(hdr.Mode)); err != nil {
                                    panic(err)
                            }
                    case tar.TypeReg:
                            ow, err := overwrite(path)
                            defer ow.Close()
                            if err != nil {
                                    panic(err)
                            }
                            if _, err := io.Copy(ow, tr); err != nil {
                                    panic(err)
                            }
                    default:
                            fmt.Printf("Can't: %c, %s\n", hdr.Typeflag, path)
                    }
            }
    }
    
    1 回复  |  直到 9 年前
        1
  •  3
  •   sberry    9 年前

    在我看来有两个问题。

    1. 您正在使用defer关闭tar编写器和gzip编写器,但defer仅在当前范围结束时执行。由于您正在运行这一功能,所以当您尝试读取到untar时,文件句柄仍将打开,这可能会导致问题(例如,可能文件尚未完全刷新)。

    2. 您没有设置 Typeflag 当您创建tarball时,在标题中。虽然GNU tar可能会处理这个问题,但假设Typeflag为“0”,Go可能不会。根据文件 http://www.gnu.org/software/tar/manual/html_node/Standard.html 常规文件的Typeflag为字节“0”。这可能意味着您需要在代码中的每个资源(目录、文件、链接等)上设置Typeflag。

    我像下面这样重写了你的代码,现在它对我有用了。(注意:将所有内容存储为REGTYPE)

    http://play.golang.org/p/3B7F_axr-i

    编辑
    啊哈,我现在知道#2的问题了。用于tar的Go库 FileInfoHeader 以便确定报头的部分,如Typeflag。自从你 文件夹 不是系统上真正的文件,它无法填写适当的Typeflag。

    GNUtar显然知道如何处理这个问题,或者可能会尽力解决这个问题,并且在这种情况下是成功的。