Go 通过gzip将命令输出到读卡器
我试图执行一个shell命令并压缩它的输出。 问题是,我需要与一个需要读卡器的API接口 为此,我尝试了以下方法(简化代码): 问题是ReadAll永远挂起。如果我关闭Go 通过gzip将命令输出到读卡器,go,Go,我试图执行一个shell命令并压缩它的输出。 问题是,我需要与一个需要读卡器的API接口 为此,我尝试了以下方法(简化代码): 问题是ReadAll永远挂起。如果我关闭gzW没有什么真正的改变。但是,如果我关闭writer变量,现在程序将在不挂起的情况下完成,但输出为: $ go test -run Pipe Waiting wait done 1f8b080000096e8800ff PASS 但是,无论我回显什么,输出都是一样的。如果我从命令行这样尝试:echo“hello_from_ec
gzW
没有什么真正的改变。但是,如果我关闭writer
变量,现在程序将在不挂起的情况下完成,但输出为:
$ go test -run Pipe
Waiting
wait done
1f8b080000096e8800ff
PASS
但是,无论我回显什么,输出都是一样的。如果我从命令行这样尝试:echo“hello_from_echo”| gzip | hextump
输出完全不同,因此这种方法有一些问题
有什么线索可能是问题吗
提前感谢您以错误的顺序关闭了gzip编写器和管道编写器。您需要关闭
gzip.Writer
以刷新所有缓冲区并写入gzip页脚,然后您可以关闭PipeWriter
以取消阻止ReadAll
。另外,添加WaitGroup
可确保您不会被任何关闭通话阻塞
cmd := exec.Command("echo", "hello_from_echo and more")
pr, pw := io.Pipe()
gzW := gzip.NewWriter(pw)
cmd.Stdout = gzW
cmd.Start()
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
err := cmd.Wait()
if err != nil {
log.Println(err)
}
gzW.Close()
pw.Close()
}()
buf, err := ioutil.ReadAll(pr)
if err != nil {
t.Fatal(err)
}
wg.Wait()
fmt.Println(hex.EncodeToString(buf))
是否不使用cmd.Wait关闭输出?(这就是gzW)现在我通过手动调用gzW上的flush解决了这个问题,但我将尝试您的解决方案并报告back@FerminSilva,不,它不叫关闭。(Cmd.Stdout是一个
io.Writer
,而不是io.WriteCloser
)。另外,如果不关闭gzip.Writer
,crc页脚将不会被写入,解压缩输出将出错。很高兴知道!顺便说一句,如果我的代码已经在gorutine中,那么在close调用上阻塞有什么问题?@FerminSilva:在gorutine中阻塞是可以的,但是在这种情况下,如果其中一个调用被阻塞,那是因为一个问题。添加了WaitGroup
,如果您先关闭管道,您将看到goroutine不会返回,因为gzip.Writer
无法关闭。最后一个问题,我是否可以(有信心地)假设,如果库需要Writer,那么我需要自己调用close,但如果库需要WriterCloser,那么它将在完成时关闭流?
cmd := exec.Command("echo", "hello_from_echo and more")
pr, pw := io.Pipe()
gzW := gzip.NewWriter(pw)
cmd.Stdout = gzW
cmd.Start()
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
err := cmd.Wait()
if err != nil {
log.Println(err)
}
gzW.Close()
pw.Close()
}()
buf, err := ioutil.ReadAll(pr)
if err != nil {
t.Fatal(err)
}
wg.Wait()
fmt.Println(hex.EncodeToString(buf))