【问题标题】:How can I use gzip on a string?如何在字符串上使用 gzip?
【发布时间】:2013-10-05 12:34:28
【问题描述】:

我想用 Go 从文件中读出一个块,把它当作 stringgzip 这个块。我知道如何从文件中读取并将其视为string,但是当涉及到compress/gzip 时,我迷路了。

我是否应该创建一个io.writer,它写入buf(字节片),使用gzip.NewWriter(io.writer) 获取w *gzip.Writer,然后使用w.Write(chunk_of_file) 将文件块写入buf?然后我需要将字符串视为字节切片。

【问题讨论】:

标签: go gzip


【解决方案1】:

您可以使用gzip.Writer 编写,因为它实现了io.Writer

例子:

package main

import (
    "bytes"
    "compress/gzip"
    "fmt"
    "log"
)

func main() {
    var b bytes.Buffer
    gz := gzip.NewWriter(&b)
    if _, err := gz.Write([]byte("YourDataHere")); err != nil {
        log.Fatal(err)
    }
    if err := gz.Close(); err != nil {
        log.Fatal(err)
    }
    fmt.Println(b.Bytes())
}

Go Playground

如果您想设置压缩级别(默认为 -1,来自 compress/flate),您可以使用 gzip.NewWriterLevel

【讨论】:

  • 我觉得应该注意的是,直到调用gz.Flush(),Writer才会真正将压缩字节写入缓冲区。也使用gz.Close() 调用flush,但playground 示例永远不会那么远。
  • 还有一件事是 Flush() 只将 current 数据写入缓冲区。它并没有完成整个 GZIP 格式。所以,在这种情况下,它是毫无用处的,因为写在最后一行的不是一个有效的 GZIP 结构。您需要在对缓冲区执行任何操作之前调用 Close()
  • @PhilKulak 感谢您的更正。我已更改示例代码以在打印缓冲区内容之前关闭编写器。
  • 你可以调用 Close()。来自 golang 文档: func (z *Writer) Close() error Close 关闭 Writer,将任何未写入的数据刷新到底层 io.Writer,但不会关闭底层 io.Writer。 golang.org/pkg/compress/gzip/#Writer.Close
  • 优秀的提示@PhilKulak。补充一点,使用 defer 关闭压缩的 Writer 可能会导致在关闭之前使用缓冲区的细微错误。这可能会在读取压缩数据时导致意外的 EOF 错误。小心!
【解决方案2】:

如果结果没有返回到文件中,那么您可以使用 Flate 直接地。您可以从 Gzip 中节省一些开销。另一种选择是 Brotli。 例子:

package main

import (
   "bytes"
   "compress/flate"
   "github.com/andybalholm/brotli"
)

func compressFlate(data []byte) ([]byte, error) {
   var b bytes.Buffer
   w, err := flate.NewWriter(&b, 9)
   if err != nil {
      return nil, err
   }
   w.Write(data)
   w.Close()
   return b.Bytes(), nil
}

func compressBrotli(data []byte) []byte {
   var b bytes.Buffer
   w := brotli.NewWriterLevel(&b, brotli.BestCompression)
   w.Write(data)
   w.Close()
   return b.Bytes()
}

结果:

package main

import (
   "bytes"
   "fmt"
)

func main() {
   data := bytes.Repeat([]byte("hello world"), 999_999)
   f, err := compressFlate(data)
   if err != nil {
      panic(err)
   }
   b := compressBrotli(data)
   fmt.Println(len(f) == 21379, len(b) == 40)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-13
    • 2010-11-24
    相关资源
    最近更新 更多