2013-06-03 54 views
24

我是golang的新手,無法弄清楚如何使用golang的「compress/gzip」包對我有利。基本上,我只想寫一些東西到一個文件,gzip它,並通過另一個腳本直接從壓縮格式讀取它。我真的很感激,如果有人可以給我一個例子如何做到這一點。如何使用golang的「compress/gzip」軟件包來gzip文件?

+0

@Nicolai感謝編輯的問題。 – pymd

回答

43

所有壓縮包都實現相同的接口。你會使用這樣的壓縮:

var b bytes.Buffer 
w := gzip.NewWriter(&b) 
w.Write([]byte("hello, world\n")) 
w.Close() 

這解壓:

r, err := gzip.NewReader(&b) 
io.Copy(os.Stdout, r) 
r.Close() 
+0

謝謝!這有幫助。 – pymd

5

幾乎相同的答案洛朗,但文件IO:

import (
    "bytes" 
    "compress/gzip" 
    "io/ioutil" 
) 
// ... 
var b bytes.Buffer 
w := gzip.NewWriter(&b) 
w.Write([]byte("hello, world\n")) 
w.Close() // You must close this first to flush the bytes to the buffer. 
err := ioutil.WriteFile("hello_world.txt.gz", b.Bytes(), 0666) 
+4

您應該使用os.Open創建文件並將其傳遞給gzip.NewWriter,並且對該gzip寫入器的每次寫入都會將壓縮數據寫入該文件。 – Giacomo

8

對於閱讀部分,有用ioutil.ReadFile.gz文件可能是:

func ReadGzFile(filename string) ([]byte, error) { 
    fi, err := os.Open(filename) 
    if err != nil { 
     return nil, err 
    } 
    defer fi.Close() 

    fz, err := gzip.NewReader(fi) 
    if err != nil { 
     return nil, err 
    } 
    defer fz.Close() 

    s, err := ioutil.ReadAll(fz) 
    if err != nil { 
     return nil, err 
    } 
    return s, nil 
} 
2

我決定結合其他人的想法,並提供一個完整的示例程序。顯然有很多不同的方法來做同樣的事情。這只是一種方式:

package main 

import (
    "compress/gzip" 
    "fmt" 
    "io/ioutil" 
    "os" 
) 

var zipFile = "zipfile.gz" 

func main() { 
    writeZip() 
    readZip() 
} 

func writeZip() { 
    handle, err := openFile(zipFile) 
    if err != nil { 
     fmt.Println("[ERROR] Opening file:", err) 
    } 

    zipWriter, err := gzip.NewWriterLevel(handle, 9) 
    if err != nil { 
     fmt.Println("[ERROR] New gzip writer:", err) 
    } 
    numberOfBytesWritten, err := zipWriter.Write([]byte("Hello, World!\n")) 
    if err != nil { 
     fmt.Println("[ERROR] Writing:", err) 
    } 
    err = zipWriter.Close() 
    if err != nil { 
     fmt.Println("[ERROR] Closing zip writer:", err) 
    } 
    fmt.Println("[INFO] Number of bytes written:", numberOfBytesWritten) 

    closeFile(handle) 
} 

func readZip() { 
    handle, err := openFile(zipFile) 
    if err != nil { 
     fmt.Println("[ERROR] Opening file:", err) 
    } 

    zipReader, err := gzip.NewReader(handle) 
    if err != nil { 
     fmt.Println("[ERROR] New gzip reader:", err) 
    } 
    defer zipReader.Close() 

    fileContents, err := ioutil.ReadAll(zipReader) 
    if err != nil { 
     fmt.Println("[ERROR] ReadAll:", err) 
    } 

    fmt.Printf("[INFO] Uncompressed contents: %s\n", fileContents) 

    // ** Another way of reading the file ** 
    // 
    // fileInfo, _ := handle.Stat() 
    // fileContents := make([]byte, fileInfo.Size()) 
    // bytesRead, err := zipReader.Read(fileContents) 
    // if err != nil { 
    //  fmt.Println("[ERROR] Reading gzip file:", err) 
    // } 
    // fmt.Println("[INFO] Number of bytes read from the file:", bytesRead) 

    closeFile(handle) 
} 

func openFile(fileToOpen string) (*os.File, error) { 
    return os.OpenFile(fileToOpen, openFileOptions, openFilePermissions) 
} 

func closeFile(handle *os.File) { 
    if handle == nil { 
     return 
    } 

    err := handle.Close() 
    if err != nil { 
     fmt.Println("[ERROR] Closing file:", err) 
    } 
} 

const openFileOptions int = os.O_CREATE | os.O_RDWR 
const openFilePermissions os.FileMode = 0660 

有這樣一個完整的例子應該有助於未來的參考。

+0

我不認爲這是一個好例子; 'openFile'應該返回'error'; 「Stat」沒有意義(也可能是沒有價值的!);來自'Write'和'Close'的任何錯誤都被忽略;等等等等。 –

+0

是的,錯誤處理可能會變得有點緊張,但它似乎是被問到的問題的有效答案。 @DaveC – mdwhatcott

+1

@DaveC,在審查了代碼並考慮了您的建議之後,我做了一些重寫。這僅僅是一個例子,但希望編輯改進了最佳實踐。感謝您的反饋。 – SunSparc

2

這裏的FUNC鍵解壓gzip文件到目標文件:

func UnpackGzipFile(gzFilePath, dstFilePath string) (int64, error) { 
    gzFile, err := os.Open(gzFilePath) 
    if err != nil { 
     return 0, fmt.Errorf("Failed to open file %s for unpack: %s", gzFilePath, err) 
    } 
    dstFile, err := os.OpenFile(dstFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0660) 
    if err != nil { 
     return 0, fmt.Errorf("Failed to create destination file %s for unpack: %s", dstFilePath, err) 
    } 

    ioReader, ioWriter := io.Pipe() 

    go func() { // goroutine leak is possible here 
     gzReader, _ := gzip.NewReader(gzFile) 
     // it is important to close the writer or reading from the other end of the 
     // pipe or io.copy() will never finish 
     defer func(){ 
      gzFile.Close() 
      gzReader.Close() 
      ioWriter.Close() 
     }() 

     io.Copy(ioWriter, gzReader) 
    }() 

    written, err := io.Copy(dstFile, ioReader) 
    if err != nil { 
     return 0, err // goroutine leak is possible here 
    } 
    ioReader.Close() 
    dstFile.Close() 

    return written, nil 
} 
+0

我想了解解決方案,你能否詳細說明爲什麼我們需要io.Pipe在這裏? – Sairam

+1

@Sairam io.Pipe允許讀取源文件,gzip源字節和動態寫入目標,無需爲源和字節分配額外的內存。 –

相關問題