为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
子衿沉夜 2021-09-10 10:14:18
我正在读取并同时解析(解码)自定义格式的文件,该文件用 zlib 压缩。我的问题是如何在不增加切片的情况下有效地解压缩然后解析未压缩的内容?我想在将其读入可重用缓冲区的同时对其进行解析。这是一个对速度敏感的应用程序,所以我想尽可能有效地阅读它。通常我会只是ioutil.ReadAll然后再次循环遍历数据来解析它。这次我想在读取它时对其进行解析,而不必增加读取它的缓冲区,以实现最高效率。基本上我在想,如果我能找到一个完美大小的缓冲区,那么我可以读入它,解析它,然后再次写入缓冲区,然后解析它等等。这里的问题是 zlib 阅读器似乎每次Read(b)调用时读取任意数量的字节;它不会填充切片。因此,我不知道完美的缓冲区大小是多少。我担心它可能会将我写入的一些数据分解成两个块,使其难以解析,因为有人说 uint64 可以分成两个读取,因此不会出现在同一个缓冲区读取中 - 或者可能可以永远不会发生,它总是以与最初写入的大小相同的块读出?最佳缓冲区大小是多少,或者有没有办法计算?如果我已将数据写入 zlib 写入器,f.Write(b []byte)在读回压缩数据时,是否有可能将相同的数据拆分为两次读取(这意味着我在解析过程中必须有历史记录),或者它是否总是在一样读?
查看完整描述

2 回答

?
慕标琳琳

TA贡献1830条经验 获得超9个赞

好的,所以我最终使用我自己的阅读器实现来解决这个问题。


基本上结构看起来像这样:


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,因为我的解析器应该在正确的位置停止。


查看完整回答
反对 回复 2021-09-10
  • 2 回答
  • 0 关注
  • 258 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信