使用golang io.pipe到tar文件的bug

时间:2017-09-12 03:26:16

标签: go pipe tar gunzip

我一直在使用io.Pipe测试代码,将tar和gunzip文件转换为tar球,然后使用tar实用程序解压缩。以下代码通过,但是解决过程一直在进行

错误: package main import ( "archive/tar" "compress/gzip" "fmt" "io" "log" "os" "path/filepath" "testing" ) func testTarGzipPipe2(t *testing.T) { src := "/path/to/file/folder" pr, pw := io.Pipe() gzipWriter := gzip.NewWriter(pw) defer gzipWriter.Close() tarWriter := tar.NewWriter(gzipWriter) defer tarWriter.Close() status := make(chan bool) go func() { defer pr.Close() // tar to local disk tarFile, err := os.OpenFile("/path/to/tar/ball/test.tar.gz", os.O_RDWR|os.O_CREATE, 0755) if err != nil { log.Fatal(err) } defer tarFile.Close() if _, err := io.Copy(tarFile, pr); err != nil { log.Fatal(err) } status <- true }() err := filepath.Walk(src, 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 } // header.Name = strings.TrimPrefix(strings.Replace(path, src, "", -1), string(filepath.Separator)) if err := tarWriter.WriteHeader(header); err != nil { return err } if info.Mode().IsDir() { return nil } fmt.Println(path) f, err := os.Open(path) if err != nil { return err } defer f.Close() if _, err := io.Copy(tarWriter, f); err != nil { return err } return nil }) if err != nil { log.Fatal(err) } pw.Close() <-status }

这个问题真的让我发疯了。已经两周了。我真的需要帮助调试。

感谢。

发展环境:去版本go1.9 darwin / amd64

{{1}}

1 个答案:

答案 0 :(得分:1)

gzipWritertarWriter上的延迟关闭调用之前,您正在关闭管道。没有错误,因为您没有检查其中任何一个关闭调用的错误。您需要按此顺序关闭tarWriter,然后关闭gzipWriter,然后关闭PipeWriter

但是,在此代码中根本没有理由使用管道,如果直接写入文件,则可以完全删除goroutine和相关的协调。

tarFile, err := os.OpenFile("/tmp/test.tar.gz", os.O_RDWR|os.O_CREATE, 0644)
if err != nil {
    log.Fatal(err)
}
defer tarFile.Close()

gzipWriter := gzip.NewWriter(tarFile)
defer gzipWriter.Close()
tarWriter := tar.NewWriter(gzipWriter)
defer tarWriter.Close()