2017-09-12 60 views
0

我一直在使用io.Pipe測試代碼,將tar和gunzip文件轉換成tar球,然後使用tar實用程序進行解壓縮。後續的代碼通過,但是untaring過程中不斷變得使用golang io.pipe到tar文件的錯誤

錯誤: tar: Truncated input file (needed 1050624 bytes, only 0 available) tar: Error exit delayed from previous errors.

這個問題真的快把我逼瘋了。已經兩週了。我真的需要幫助調試。

謝謝。

開發環境:去版本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來等待goroutines。 – JimB

回答

1

gzipWritertarWriter遞延關閉呼叫之前,您正在關閉管道。沒有錯誤,因爲您沒有檢查這兩個關閉呼叫中的錯誤。您需要依次關閉tarWriter,然後關閉gzipWriter,然後關閉PipeWriter

但是,在這段代碼中根本沒有理由使用pipe,如果直接寫入文件,可以刪除goroutine和相關的協調。

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

我忘記的一件重要事情是以相反的順序關閉打開的作者。希望別人能從我的錯誤中吸取教訓。再次感謝@ JimB。 – NSTNF

+0

@NSTNF:實際上你有'tarWriter.Close()'和'gzipWriter.Close()'正確,延遲調用按LIFO順序執行。 – JimB

+0

謝謝。 Golang與其他langs不同。它要求開發人員改變編碼思想。我努力正確編碼,然後高效地進行編碼。打開的作家需要以相反的順序關閉。這可能是一個常見的錯誤。如果創建一個常見的錯誤wiki或者在關閉gzip writer之前添加諸如「warning:關閉tar作家」之類的東西給相應的golang文檔,會對其他開發者有利嗎? – NSTNF