部分GZ解压是否可行?

15

针对以 .gz 文件格式存储的图片(因为我的图片处理软件可以读取 .gz 格式文件,以节省磁盘空间和时间),我需要检查每个文件的头部。

头部只是每张图片起始处的一个小结构体,大小固定。对于未压缩的图片,检查头部非常快速。而对于读取压缩图片,我别无选择,只能解压整个文件然后检查头部,这当然会减慢程序运行速度。

是否可能仅读取 .gz 文件的前一段(比如几KB),解压这一段并读取原内容呢?据我对 .gz 的理解,经过初始某些簿记工作之后,压缩数据是按顺序存储的 —— 这样说正确吗?

所以,不再:
1. 打开大文件 F
2. 解压大文件 F
3. 读取 500 字节的头部
4. 重新压缩大文件 F

而改为:
1. 打开大文件 F
2. 从 F 中读取前 5K 作为流 A
3. 将 A 解压缩成流 B
4. 从 B 中读取 500 字节的头部

我使用的是 libz.so,但也欢迎其他语言的解决方案!

3个回答

20
你可以使用 gzip -cd file.gz | dd ibs=1024 count=10 来解压前10 KiB的内容。 gzip -cd 会将输出内容解压缩到标准输出中。
管道符 | 将此操作传递给 dd 实用程序。 dd 实用程序将标准输入复制到标准输出。所以,dd ibs=1024 可以设置输入块大小为1024字节,而不是默认的512字节。 count=10 表示只复制10个输入块,因此停止gzip解压缩过程。
如果你想使用标准的512块大小并忽略多余的12字节,请使用 gzip -cd file.gz | dd count=1
一条评论指出,你可以使用 gzip -cd file.gz | head -c $((1024*10)) 或在这种特殊情况下使用 gzip -cd file.gz | head -c $(512)。原始的 dd 依赖于gzip在1024中解压缩的事实似乎不正确。例如,dd ibs=2 count=10 解压缩前20个字节。

4
请注意,使用 dd 的这种方式取决于 gzip 以1024字节的倍数写入,因为 dd 是块取向的(读系统调用的数量),而不是字节取向的。请使用 head -c $((1024*10)),这种方法更简单、更高效。请参考相关的如何部分提取压缩的大型纯文本文件? - Peter Cordes

4
是的,这是可能的。
但不要重复造轮子,HDF5 数据库支持不同的压缩算法(其中包括gz),并且您可以访问不同的部分。它与Linux和Windows兼容,并且有许多语言的包装器。如果使用高压缩率,它还支持并行读取和解压缩,这非常有用。
下面是通过PyTables使用不同压缩算法从Python中读取速度的比较图表:Plot

感谢您提供的信息和确认!但我的问题比较基础:首先,我需要使用我所获得的数据和其他软件(仅限.gz格式)。此外,我在HDF5页面上没有看到部分解压缩的应用/提供?这是我唯一需要的;HDF5看起来是一个非常复杂的产品。 - alle_meije
从数据库中读取数据的函数是H5Dread,位于src/H5DIo.c中。您可以阅读源代码并查看它们如何实现。除此之外,很抱歉我无法为您提供更多帮助。 - Davidmh

0
一个 Deflate 流可以有多个块依次排列。但是你总是可以仅解压缩你想要的字节数,即使它是更大块的一部分。zlib 函数 gzread 接受长度参数,还有其他各种方法可以解压缩特定数量的明文字节,而不管完整流的长度如何。请参见 the zlib manual 以获取函数列表和如何使用它们的信息。
如果您只想修改标题,则不清楚是否如此。 (您提到重新压缩整个文件,但选项B不会重新压缩任何内容)。如果是这样,请在单独的Deflate块中编写标题,以便可以替换该块而无需重新压缩图像的其余部分。调用zlib deflate 函数时使用 Z_FULL_FLUSH 来编写标题时。您可能不需要在任何地方记录标题的压缩长度;我认为可以在读取它们以确定要替换哪些字节时计算出来。
如果您没有修改任何内容,则重新压缩整个文件毫无意义。找到您喜欢的标题后,您可以从头开始进行查找和重新启动解压缩...

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