dsdf64562672 2016-10-28 19:55 采纳率: 0%
浏览 37
已采纳

通过gzip将命令输出到Reader

I'm trying to execute a shell command and compress it's output. The problem is that I then need to interface with an API that expects a Reader.

For that I tried with the following (simplified code):

package main

import (
    "encoding/hex"
    "testing"
    "fmt"
    "io"
    "io/ioutil"
    "os/exec"
    "compress/gzip"
)

func TestPipe(t *testing.T) {
    cmd := exec.Command("echo", "hello_from_echo")

    reader, writer := io.Pipe()
    gzW := gzip.NewWriter(writer)

    cmd.Stdout = gzW 
    cmd.Start()

    go func() {
        fmt.Println("Waiting")
        cmd.Wait()
        fmt.Println("wait done")
        // writer.Close()
        // gzW.Close()
    }()

    msg, _ := ioutil.ReadAll( reader )
    fmt.Println( hex.EncodeToString( msg ) )
}

The problem is that ReadAll hangs forever. If I close gzW nothing really changes. However, if I close the writer variable, now the program finishes without hanging, but the output is:

$ go test -run Pipe
Waiting
wait done
1f8b080000096e8800ff
PASS

However, no matter what I echo the output is the same. If I try it from the command line like this: echo "hello_from_echo" | gzip | hexdump the output is totally different, so there's something wrong with that approach.

Any clue what could be the problem?

Thanks in advance

  • 写回答

1条回答 默认 最新

  • dsdt66064367 2016-10-28 20:50
    关注

    You're closing the gzip writer and pipe writer in the wrong order. You need to close the gzip.Writer to flush any buffers and write the gzip footer, then you can close the PipeWriter to unblock the ReadAll. Also adding the WaitGroup ensures that you're not blocked on any of the close calls.

    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))
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 救!ENVI5.6深度学习初始化模型报错怎么办?
  • ¥30 eclipse开启服务后,网页无法打开
  • ¥30 雷达辐射源信号参考模型
  • ¥15 html+css+js如何实现这样子的效果?
  • ¥15 STM32单片机自主设计
  • ¥15 如何在node.js中或者java中给wav格式的音频编码成sil格式呢
  • ¥15 不小心不正规的开发公司导致不给我们y码,
  • ¥15 我的代码无法在vc++中运行呀,错误很多
  • ¥50 求一个win系统下运行的可自动抓取arm64架构deb安装包和其依赖包的软件。
  • ¥60 fail to initialize keyboard hotkeys through kernel.0000000000