2017-09-12 1 views
0

io.Pipeを使ってファイルをtarとgunzipでタールボールにし、tarユーティリティを使って解凍するコードをテストしています。 tar: Truncated input file (needed 1050624 bytes, only 0 available) tar: Error exit delayed from previous errors.golang io.pipeからtarファイルへのバグバグ

この問題は本当に狂気私を運転している:次のコードは合格、しかしuntaringプロセスは

エラーを取得して保持します。それは2週間続いた。私は本当にデバッグを助ける必要があります。

ありがとうございました。

開発的環境:バージョン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 
} 
+2

エラーは何ですか?また、ファイルに 'fmt'を実行してください – reticentroot

+0

関連性がありません:テストで(または' defer'文を実行すると予想される)log.Fatalを呼び出すべきではありません。失敗したテスト。あなたが望むことをする 't.Fatal'があります。 tarファイルは実行可能ではありません。シグナルとしてセンチネル値を送信するのではなく、チャネルを閉じるか、またはより良い方法として、 'WaitGroup'を使用してゴルーチンを待つようにします。 – JimB

答えて

1

あなたがgzipWritertarWriterに係る繰延閉じる呼び出し前にパイプを閉じています。これらのクローズコールのいずれかでエラーをチェックしていないので、エラーはありません。 tarWriterを閉じ、次にgzipWriterを閉じ、次にPipeWriterを順番に閉じる必要があります。

しかし、このコードではパイプを使用する理由は全くありません。ファイルに直接書き込むと、ゴルーチンと関連するコーディネーションを完全に削除することができます。

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() 
+0

私が忘れた重要なことの1つは、開かれた作家を逆の順序で閉じることです。他の人が私の間違いから学ぶことができると思う。 @ JimBにもう一度感謝します。 – NSTNF

+0

@NSTNF:実際には 'tarWriter.Close()'と 'gzipWriter.Close()'が正しくあり、遅延呼び出しはLIFOの順序で実行されます。おかげさまで – JimB

+0

ゴランは他のラングとは異なります。それは開発者がコーディング・マインド・セットを変更する必要があります私は正しく、効率的にコードを書くよう努めています。開かれた作家は逆の順序で閉じなければならない。これはよくある間違いかもしれません。一般的な間違いwikiを作成したり、gzipライターを閉じる前に "warning:close tar writer"のようなものを追加することは、他の開発者にとって有益でしょうか? – NSTNF

関連する問題