如何解压部分的zlib文件

7
我有一个文件的连续2/3部分,该文件使用zlib的deflate()函数进行了压缩。最后1/3在传输中丢失。原始未压缩文件大小为600KB。
发射器将原始文件切成2KB的块,并传递Z_NO_FLUSH直到文件结束时通过Z_FINISH多次调用Deflate。生成的完整压缩文件已被传输,但是部分数据已丢失。
是否可能恢复原始文件的一部分?如果可以,请提供建议。
我正在使用ZLIB的纯C实现和/或Python 2.7实现。
3个回答

15

虽然我不懂Python,但我成功地使这个工作了:

#!/usr/bin/python
import sys
import zlib
f = open(sys.argv[1], "rb")
g = open(sys.argv[2], "wb")
z = zlib.decompressobj()
while True:
    buf = z.unconsumed_tail
    if buf == "":
        buf = f.read(8192)
        if buf == "":
            break
    got = z.decompress(buf)
    if got == "":
        break
    g.write(got)

这应该从您的部分zlib文件中提取所有可用的内容。


谢谢,是的,使用decompressobj()函数起作用了。我之前只是使用zlib.decompress()函数,但是它一直报错。现在使用dc_obj = zlib.decompressobj()和decomp_data_str = dc_obj.decompress(orig_data_str)解决了这个问题。 - JohnSantaFe

3

更新:正如@Mark Adler指出的那样,可以使用zlib.decompressobj解压部分内容:

>>> decompressor = zlib.decompressobj()
>>> decompressor.decompress(part)
"let's compress some t"

其中part的定义如下。

--- 旧评论如下:

默认情况下,在Python中zlib不处理部分内容。

以下是有效的:

>>> compressed = "let's compress some text".encode('zip')
>>> compressed
'x\x9c\xcbI-Q/VH\xce\xcf-(J-.V(\xce\xcfMU(I\xad(\x01\x00pX\t%'
>>> compressed.decode('zip')
"let's compress some text"

如果我们截断它,它就无法工作:

>>> part = compressed[:3*len(compressed)/4]
>>> part.decode('zip')
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File ".../lib/python2.7/encodings/zlib_codec.py", lin
e 43, in zlib_decode
    output = zlib.decompress(input)
error: Error -5 while decompressing data: incomplete or truncated stream

如果我们明确使用 zlib,那么效果是一样的:
>>> import zlib
>>> zlib.decompress(compressed)
"let's compress some text"
>>> zlib.decompress(part)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
error: Error -5 while decompressing data: incomplete or truncated stream

0

以下理论上看起来是可行的,但需要对低级别的zlib例程进行调整才能实现。在http://www.zlib.net/zlib_how.html中,我们可以找到一个示例程序zpipe.c,并在其逐行描述中发现:

CHUNK只是用于向zlib例程提供数据和拉取数据的缓冲区大小。较大的缓冲区大小会更有效,特别是对于inflate()。如果有足够的内存,应该使用128K或256K字节左右的缓冲区大小。

#define CHUNK 16384
...

这是我的建议:将缓冲区设置得非常小 - 如果支持的话,甚至可以设置为单个字节。这样,您将尽可能多地解压缩数据,直到不可避免的Z_BUF_ERROR出现。在那时,通常会丢弃已收集的数据(查找过早的deflate_end调用,以便在您背后“清理”),但在您的情况下,您可以简单地流式传输到文件并在发现无法继续时关闭它。

输出的最后几个字节可能包含垃圾,如果错误的“final”符号被解码,或者zlib可能会过早中止,而不是输出部分符号。但是,您知道您的数据无论如何都将不完整,因此这不应该成为问题。


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