在Golang中读取Zlib压缩文件的最有效方法是什么?

4
我正在读取和解析(解码)一个使用zlib压缩的自定义格式文件。我的问题是如何在不增加切片大小的情况下高效地解压缩并解析未压缩的内容?我想在读入可重用缓冲区时进行解析。
由于这是一个速度敏感的应用程序,因此我希望尽可能高效地读取它。通常,我会使用ioutil.ReadAll来读取数据,然后再通过循环解析数据。这一次,我想在读取数据时进行解析,而不必将其读入需要增大的缓冲区中,以实现最大的效率。
基本上,我认为如果我能找到一个完美大小的缓冲区,那么我就可以将其读入、解析,然后再次覆盖该缓冲区,然后再次解析等等。但问题在于,zlib读取器每次调用Read(b)时似乎都会读取任意数量的字节;它不会填充切片。因此,我不知道完美的缓冲区大小是多少。我担心它可能会将我写入的某些数据分成两块,使得解析变得困难,因为一些uint64可能被分成两个读取,因此不能在同一缓冲区读取 - 或者这种情况永远不会发生,总是以与最初写入的大小相同的块读取?
  1. 什么是最优缓冲区大小?或者是否有一种方法可以计算出这个值?
  2. 如果我使用f.Write(b []byte)将数据写入zlib编写器中,那么在读回压缩数据时,可能会将同样的数据分成两部分(这意味着我在解析期间必须拥有历史记录),还是它总是以相同的方式读取?
2个回答

0

好的,最后我用自己实现的读取器解决了这个问题。

基本上,结构看起来是这样的:

type reader struct {
 at int
 n int
 f io.ReadCloser
 buf []byte
}

这可以附加到zlib读取器:

// Open file for reading
fi, err := os.Open(filename)
if err != nil {
    return nil, err
}
defer fi.Close()
// Attach zlib reader
r := new(reader)
r.buf = make([]byte, 2048)
r.f, err = zlib.NewReader(fi)
if err != nil {
    return nil, err
}
defer r.f.Close()

然后可以使用类似于这样的函数从zlib读取器中直接读取x个字节:

mydata := r.readx(10)

func (r *reader) readx(x int) []byte {
    for r.n < x {
        copy(r.buf, r.buf[r.at:r.at+r.n])
        r.at = 0
        m, err := r.f.Read(r.buf[r.n:])
        if err != nil {
            panic(err)
        }
        r.n += m
    }
    tmp := make([]byte, x)
    copy(tmp, r.buf[r.at:r.at+x]) // must be copied to avoid memory leak
    r.at += x
    r.n -= x
    return tmp
}

请注意,我无需检查EOF,因为我的解析器应该在正确的位置停止。

0

您可以将zlib读取器包装在bufio读取器中,然后在其上实现一个专用的读取器,通过从bufio读取器中读取数据重建数据块,直到完整的数据块被读取。请注意,bufio.Read在底层读取器上仅调用Read 一次,因此您需要在循环中调用ReadByte。但是bufio将为您处理由zlib读取器返回的不可预测的数据大小。

如果您不想实现专用的读取器,您可以使用bufio读取器并使用ReadByte()读取尽可能多的字节以填充给定的数据类型。最佳缓冲区大小至少为最大数据结构的大小,最多可以塞入内存。

如果直接从zlib读取器中读取,则不能保证您的数据不会在两次读取之间被分割。

另一种也许更简洁的解决方案是为您的数据实现一个写入器,然后使用io.Copy(your_writer,zlib_reader)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接