2016-10-28 3 views
1

私はシェルコマンドを実行して、その出力を圧縮しようとしています。 問題は、Readerを必要とするAPIとのインターフェースが必要なことです。 Iは、以下の(簡略化コード)としようとしたことについてgzipからReaderへのパイプコマンド出力

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)) 
} 

問題はREADALLは永遠ハングすることです。もし私がgzWを閉じても何も変わりません。しかし、私はwriter変数を閉じると、今のプログラムはハングせずに終了しますが、出力は次のようになります。

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

しかし、関係なく、私はエコー何の出力が同じではありません。私がこのようなコマンドラインから試してみると、echo "hello_from_echo" | gzip | hexdumpの出力はまったく違うので、そのアプローチには何か問題があります。

何か問題が発生する可能性がありますか?

おかげで、事前

答えて

2

にあなたは間違った順序での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)) 
+0

出力を閉じないでください。 (これはgzWです) 今のところ、手動​​でgzWでflushを呼び出すことで解決しましたが、解決策を試してみて –

+0

@FerminSilva、いいえ、Closeを呼び出さないでください。 (Cmd.Stdoutは 'io.Writer'であり、' io.WriteCloser'ではありません)。また、 'gzip.Writer'を閉じなければ、crcフッターは書き込まれず、出力の解凍はエラーになります。 – JimB

+0

知っておいてよかった!ところで、私のコードが既にgorutineに入っている場合、クローズコールのブロックに関する問題は何ですか? –

関連する問題