2013-06-03 53 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源字节和动态写入目标,无需为源和字节分配额外的内存。 –

相关问题