我正在读取并同时解析(解码)自定义格式的文件,该格式使用zlib压缩。我的问题是如何有效地解压缩然后解析未压缩的内容而不增加切片?我想解析它,同时将其读入可重用的缓冲区。
这适用于对速度敏感的应用程序,因此我希望尽可能高效地阅读它。通常我会ioutil.ReadAll
然后再循环遍历数据来解析它。这次我想在阅读时解析它,而不必增加读取的缓冲区,以获得最大效率。
基本上我认为如果我能找到一个完美大小的缓冲区,那么我可以读入它,解析它,然后再次写入缓冲区,然后解析它等等。这里的问题是zlib每次调用Read(b)
时,阅读器似乎都会读取任意数量的字节;它没有填补切片。因此,我不知道完美的缓冲区大小是多少。我担心它可能会破坏我写入两个块的一些数据,因此很难解析,因为有人说uint64可以从两个读取中分离出来,因此不会出现在相同的缓冲区读取中 - 或者可能是永远不会发生,并且它总是以与最初编写的相同大小的块读出来?
f.Write(b []byte)
将数据写入zlib编写器,则在读回压缩数据时可能会将这些相同的数据拆分为两个读数(意味着我必须在解析过程中获得历史记录),或者它会一直回到同一个阅读中吗?答案 0 :(得分:0)
您可以将zlib阅读器包装在bufio阅读器中,然后在顶部实现专用阅读器,通过从bufio阅读器读取来重建您的数据块,直到读取完整的块。请注意,bufio.Read在底层Reader上最多调用一次,因此您需要在循环中调用ReadByte。但是,bufio将为您处理zlib阅读器返回的不可预测的数据大小。
如果您不想实现专门的阅读器,您可以使用bufio阅读器并使用ReadByte()根据需要读取尽可能多的字节以填充给定的数据类型。最佳缓冲区大小至少是您最大的数据结构的大小,直到您可以进入内存的任何内容。
如果直接从zlib阅读器上阅读,则无法保证您的数据不会在两次读取之间分开。
另一种可能更清晰的解决方案是为您的数据实现一个编写器,然后使用io.Copy(your_writer,zlib_reader)。
答案 1 :(得分: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,因为我的解析器应该在正确的位置停止。