从Go中的tar文件中提取

时间:2015-08-27 16:21:13

标签: go gzip tar

此代码尝试将某些文本转换为tar文件并解压缩。 tar的代码有效但看起来我做错了 因为untar同一个文件不起作用。

当我解压缩手动tar.gz与OS 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 个答案:

答案 0 :(得分:2)

在我看来,有两个问题。

  1. 您正在使用defer关闭tar writer和gzip writer,但是只在当前作用域结束时才执行。由于您在一个函数中运行此函数,因此当您尝试读取untar并且可能导致问题(例如文件未完全刷新)时,文件句柄仍将打开。

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

  3. 我重写了以下代码,现在它正在为我工​​作。 (注意:将所有内容存储为REGTYPE)

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

    修改
    啊哈,我现在知道#2的问题了。 tar的Go库使用FileInfoHeader来确定标题的部分,如Typeflag。由于您的文件不是系统上的真正文件,因此无法填写相应的Typeflag。

    GNU tar显然知道如何处理这个问题,或者也许会尽力解决这个问题并在这种情况下取​​得成功。