Go 通过gzip将命令输出到读卡器

Go 通过gzip将命令输出到读卡器,go,Go,我试图执行一个shell命令并压缩它的输出。 问题是,我需要与一个需要读卡器的API接口 为此,我尝试了以下方法(简化代码): 问题是ReadAll永远挂起。如果我关闭gzW没有什么真正的改变。但是,如果我关闭writer变量,现在程序将在不挂起的情况下完成,但输出为: $ go test -run Pipe Waiting wait done 1f8b080000096e8800ff PASS 但是,无论我回显什么,输出都是一样的。如果我从命令行这样尝试:echo“hello_from_ec

我试图执行一个shell命令并压缩它的输出。 问题是,我需要与一个需要读卡器的API接口

为此,我尝试了以下方法(简化代码):

问题是ReadAll永远挂起。如果我关闭
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))