在Golang中读取Zlib压缩文件的最有效方法?
我正在读取并同时解析(解码)一个自定义格式的文件,该文件用zlib压缩。我的问题是如何在不增加切片的情况下有效地解压缩并解析未压缩的内容?我希望在将其读入可重用缓冲区时对其进行解析 这是一个速度敏感的应用程序,所以我希望尽可能高效地阅读它。通常我只是在Golang中读取Zlib压缩文件的最有效方法?,go,zlib,Go,Zlib,我正在读取并同时解析(解码)一个自定义格式的文件,该文件用zlib压缩。我的问题是如何在不增加切片的情况下有效地解压缩并解析未压缩的内容?我希望在将其读入可重用缓冲区时对其进行解析 这是一个速度敏感的应用程序,所以我希望尽可能高效地阅读它。通常我只是ioutil.ReadAll,然后再次循环遍历数据来解析它。这一次,我想在读取时解析它,而不必增加读取它的缓冲区,以获得最大的效率 基本上我在想,如果我能找到一个完美大小的缓冲区,那么我可以读入这个,解析它,然后再次写缓冲区,然后解析它,等等。这里的
ioutil.ReadAll
,然后再次循环遍历数据来解析它。这一次,我想在读取时解析它,而不必增加读取它的缓冲区,以获得最大的效率
基本上我在想,如果我能找到一个完美大小的缓冲区,那么我可以读入这个,解析它,然后再次写缓冲区,然后解析它,等等。这里的问题是,zlib读取器似乎在每次调用read(b)
时读取任意数量的字节;它不能填满切片。正因为如此,我不知道什么是完美的缓冲区大小。我担心它可能会将我写入的一些数据分成两个块,这使得解析变得困难,因为有人说uint64可能会被分成两个读取,因此不会发生在同一个缓冲区读取中——或者可能永远不会发生这种情况,并且它总是以与最初写入的相同大小的块进行读取
f.Write(b[]byte)
将数据写入zlib writer,那么在读取压缩数据时,是否可能将相同的数据拆分为两次读取(这意味着在解析过程中我必须有一个历史记录),或者它总是以相同的读取方式返回您可以将zlib读取器封装在bufio读取器中,然后在其顶部实现一个专门的读取器,该读取器将通过读取bufio读取器直到读取完整的数据块来重建数据块。请注意,bufio.Read在底层读取器上最多调用Read一次,因此需要在循环中调用ReadByte。但是,bufio将为您处理zlib读取器返回的不可预测的数据大小 如果不想实现专门的读取器,可以使用bufio读取器,通过ReadByte()读取所需的字节数,以填充给定的数据类型。最佳缓冲区大小至少是最大数据结构的大小,最多可以放入内存 如果直接从zlib读卡器读取数据,则无法保证数据不会在两次读取之间分割
另一个可能更干净的解决方案是为您的数据实现一个writer,然后使用io.Copy(您的writer,zlib\u reader)。好的,所以最后我用自己的阅读器实现解决了这个问题 结构基本上如下所示:
type reader struct {
at int
n int
f io.ReadCloser
buf []byte
}
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
}
可将其连接到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个字节:
type reader struct {
at int
n int
f io.ReadCloser
buf []byte
}
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
}
mydata:=r.readx(10)
func(r*读取器)readx(x int)[]字节{
对于r.n
注意,我不需要检查EOF,因为我认为我的解析器应该在正确的位置停止