使用golang io.pipe到tar文件的错误
我一直在使用io.Pipe测试代码,将tar和gunzip文件转换成tar球,然后使用tar实用程序进行解压缩。后续的代码通过,但是untaring过程中不断变得使用golang io.pipe到tar文件的错误
错误: tar: Truncated input file (needed 1050624 bytes, only 0 available) tar: Error exit delayed from previous errors.
这个问题真的快把我逼疯了。已经两周了。我真的需要帮助调试。
谢谢。
开发环境:去版本go1.9达尔文/ AMD64
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
}
在gzipWriter
和tarWriter
递延关闭呼叫之前,您正在关闭管道。没有错误,因为您没有检查这两个关闭呼叫中的错误。您需要依次关闭tarWriter
,然后关闭gzipWriter
,然后关闭PipeWriter
。
但是,在这段代码中根本没有理由使用pipe,如果直接写入文件,可以删除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()
我忘记的一件重要事情是以相反的顺序关闭打开的作者。希望别人能从我的错误中吸取教训。再次感谢@ JimB。 – NSTNF
@NSTNF:实际上你有'tarWriter.Close()'和'gzipWriter.Close()'正确,延迟调用按LIFO顺序执行。 – JimB
谢谢。 Golang与其他langs不同。它要求开发人员改变编码思想。我努力正确编码,然后高效地进行编码。打开的作家需要以相反的顺序关闭。这可能是一个常见的错误。如果创建一个常见的错误wiki或者在关闭gzip writer之前添加诸如“warning:关闭tar作家”之类的东西给相应的golang文档,会对其他开发者有利吗? – NSTNF
什么是错误?还请'去fmt'文件 – reticentroot
不相关:你不应该在测试中(或者你期望执行'defer'语句的任何地方)调用log.Fatal,因为它阻止了你打算做的任何清理,并且可以隐藏未通过测试。有一个't.Fatal'这是你想要的。一个tar文件不应该是可执行的。关闭一个通道而不是发送一个标记值作为信号,或者更好的是,使用WaitGroup来等待goroutines。 – JimB