2013-06-03 43 views
24

Tôi mới đến golang, và không thể tìm ra cách sử dụng gói "nén/gzip" của golang cho lợi thế của tôi. Về cơ bản, tôi chỉ muốn viết một cái gì đó vào một tập tin, gzip nó và đọc nó trực tiếp từ định dạng nén thông qua một kịch bản khác. Tôi thực sự sẽ đánh giá cao nếu ai đó có thể cho tôi một ví dụ về cách làm điều này.Tôi làm cách nào để sử dụng gói "nén/gzip" của golang để gzip một tệp?

+0

@Nicolai nhờ để chỉnh sửa câu hỏi. – pymd

Trả lời

43

Tất cả các gói nén đều triển khai cùng một giao diện. Bạn sẽ sử dụng một cái gì đó như thế này để nén:

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

Và điều này để giải nén:

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

cảm ơn! Điều này đã giúp. – pymd

5

Khá nhiều câu trả lời tương tự như Laurent, nhưng với file 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

Bạn chỉ cần tạo tệp bằng os.Open và chuyển nó tới gzip.NewWriter và mọi ghi vào gzip writer đó sẽ ghi dữ liệu nén vào tệp đó. – Giacomo

8

Đối phần Đọc, một cái gì đó giống như hữu ích ioutil.ReadFile cho .gz tệp có thể là:

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

Tôi quyết định kết hợp các ý tưởng từ những câu trả lời khác và chỉ cung cấp một chương trình ví dụ đầy đủ. Rõ ràng có rất nhiều cách khác nhau để làm điều tương tự. Đây chỉ là một cách:

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 

Có ví dụ đầy đủ như thế này sẽ hữu ích để tham khảo trong tương lai.

+0

Tôi không nghĩ đây là một ví dụ hay; 'openFile' sẽ trả về' error'; không có điểm nào làm 'Stat' (cũng có thể là giá trị nil!); bất kỳ lỗi nào từ 'Write' và' Close' đều bị bỏ qua; v.v. –

+0

Có, việc xử lý lỗi có thể được tăng cường một chút, nhưng nó dường như là một câu trả lời hợp lệ cho câu hỏi đang được hỏi. @DaveC – mdwhatcott

+1

@DaveC, sau khi xem xét mã và xem xét đề xuất của bạn, tôi đã làm một chút viết lại. Đây chỉ là một ví dụ, nhưng hy vọng bản chỉnh sửa đã cải thiện các phương pháp hay nhất. Cảm ơn bạn đã phản hồi. – SunSparc

2

Ở đây func cho file gzip giải nén để file đích:

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

Tôi đang cố gắng hiểu giải pháp, bạn có thể nêu chi tiết tại sao chúng tôi cần io.Pipe ở đây không? – Sairam

+1

@Sairam io.Pipe cho phép đọc nguồn, byte nguồn gzip và ghi vào đích khi đang di chuyển, mà không cần cấp phát thêm bộ nhớ cho nguồn và byte được mã hóa. –