关于压缩:python中的zlib解压缩

zlib decompression in python

好的,我有一些通过python(2.6)zlib.compress()函数压缩的数据流。 当我尝试解压缩它们时,其中一些将不会解压缩(zlib错误-5,这似乎是"缓冲区错误",不知道该怎么做)。 起初,我以为我已经完成了,但是我意识到我无法解压缩的所有内容都从0x78DA开始(工作的是0x789C),我环顾四周,这似乎是另一种zlib压缩- 幻数根据所使用的压缩而变化。 我可以用什么解压缩文件? 我在用软管吗?


根据RFC 1950," OK" 0x789C和"坏" 0x78DA之间的区别在于FLEVEL位字段:

1
2
3
4
5
6
7
8
9
10
11
12
  FLEVEL (Compression level)
     These flags are available for use by specific compression
     methods.  The"deflate" method (CM = 8) sets these flags as
     follows:

        0 - compressor used fastest algorithm
        1 - compressor used fast algorithm
        2 - compressor used default algorithm
        3 - compressor used maximum compression, slowest algorithm

     The information in FLEVEL is not needed for decompression; it
     is there to indicate if recompression might be worthwhile.

"确定"使用2,"不良"使用3。因此,其本身的区别不成问题。

为了进一步了解,您可能考虑为压缩和(尝试的)解压缩中的每一个提供以下信息:什么平台,什么版本的Python,什么版本的zlib库,什么是用来调用zlib模块的实际代码。还应提供来自失败的解压缩尝试的完整回溯和错误消息。您是否尝试过使用任何其他zlib读取软件解压缩失败的文件?结果如何?请说明您要使用的工具:"我在用软管吗?"意味着您无权访问原始数据?它是如何从流传输到文件的?您如何保证数据不被传输破坏?

更新基于您的自我解答中发布的部分澄清的一些观察结果:

您正在使用Windows。 Windows在读写文件时区分二进制模式和文本模式。在文本模式下阅读时,Python 2.x将' r n'更改为' n',在编写时将' n'更改为' r n'。在处理非文本数据时,这不是一个好主意。更糟糕的是,在文本模式下阅读时,' x1a'又名Ctrl-Z被视为文件结尾。

压缩文件:

1
2
3
4
5
6
# imports and other superstructure left as a exercise
str_object1 = open('my_log_file', 'rb').read()
str_object2 = zlib.compress(str_object1, 9)
f = open('compressed_file', 'wb')
f.write(str_object2)
f.close()

要解压缩文件:

1
2
3
4
5
str_object1 = open('compressed_file', 'rb').read()
str_object2 = zlib.decompress(str_object1)
f = open('my_recovered_log_file', 'wb')
f.write(str_object2)
f.close()

另外:最好使用gzip模块,这样可以省去一些麻烦,例如文本模式,但会花费一些字节的额外标题信息。

如果您一直在压缩代码中使用'rb'和'wb'而不在解压缩代码中使用[不太可能?],那么您就不用管了,您只需要充实上述解压缩代码并继续使用即可。

在以下未经测试的想法中,请仔细注意" may"," should"等的使用。

如果您未在压缩代码中使用" rb"和" wb",则使用软管进行压缩的可能性非常高。

如果原始文件中有任何' x1a'实例,则第一个此类文件之后的任何数据都会丢失-但在这种情况下,解压缩时不会失败(IOW,这种情况与您的症状不符)。

如果Ctrl-Z由zlib本身生成,则这将在尝试进行解压缩时导致早期的EOF,这当然会导致异常。在这种情况下,您可以通过以二进制模式读取压缩文件,然后用' n'替换' r n'来谨慎地逆转该过程[模拟文本模式,而无需按Ctrl-Z-> EOF gi头]。解压缩结果。编辑在TEXT模式下将结果写出。结束编辑

更新2我可以使用以下脚本从1到9的任何级别重现您的症状:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import zlib, sys
fn = sys.argv[1]
level = int(sys.argv[2])
s1 = open(fn).read() # TEXT mode
s2 = zlib.compress(s1, level)
f = open(fn + '-ct', 'w') # TEXT mode
f.write(s2)
f.close()
# try to decompress in text mode
s1 = open(fn + '-ct').read() # TEXT mode
s2 = zlib.decompress(s1) # error -5
f = open(fn + '-dtt', 'w')
f.write(s2)
f.close()

注意:您将需要使用相当大的文本文件(我使用了80kb的源文件)来确保解压缩结果将包含' x1a'。

我可以使用以下脚本恢复:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import zlib, sys
fn = sys.argv[1]
# (1) reverse the text-mode write
# can't use text-mode read as it will stop at Ctrl-Z
s1 = open(fn, 'rb').read() # BINARY mode
s1 = s1.replace('

'
, '
'
)
# (2) reverse the compression
s2 = zlib.decompress(s1)
# (3) reverse the text mode read
f = open(fn + '-fixed', 'w') # TEXT mode
f.write(s2)
f.close()

注意:如果原始文件中有一个' x1a'aka Ctrl-Z字节,并且以文本模式读取该文件,则该字节和所有后续字节将不包含在压缩文件中,因此无法恢复。对于文本文件(例如源代码),这完全没有损失。对于二进制文件,很可能已被清理。

更新3 [后来发现该问题涉及加密/解密层]:

"错误-5"消息表明,您尝试解压缩的数据自压缩以来已被篡改。如果不是由于在文件上使用文本模式引起的,则怀疑显然是由解密和加密包装程序引起的。如果需要帮助,则需要透露这些包装的来源。实际上,您应该尝试做的是(就像我一样)将一个小的脚本放在一起,以便在多个输入文件上重现该问题。其次(就像我一样),看看是否可以在什么条件下撤消该过程。如果您需要第二阶段的帮助,则需要泄漏问题重现脚本。


我正寻找

1
python -c 'import sys,zlib;sys.stdout.write(zlib.decompress(sys.stdin.read()))'

我自己写的基于python中zlib解压缩的答案


好的,很抱歉,我的上一篇文章,我没有所有内容。而且由于我没有使用OpenID,所以我无法编辑自己的帖子。无论如何,这里有一些数据:

1)减压回溯:

1
2
3
4
Traceback (most recent call last):
  File"<my file>", line 5, in <module>
    zlib.decompress(data)
zlib.error: Error -5 while decompressing data

2)压缩码:

1
2
3
4
5
#here you can assume the data is the data to be compressed/stored
data = encrypt(zlib.compress(data,9)) #a short wrapper around PyCrypto AES encryption
f = open("somefile", 'wb')
f.write(data)
f.close()

3)减压码:

1
2
3
4
5
f = open("somefile", 'rb')
data = f.read()
f.close()

zlib.decompress(decrypt(data)) #this yeilds the error in (1)

好的,抱歉,我还不够清楚。这是Win32,Python 2.6.2。恐怕我找不到zlib文件,但是无论它在win32二进制发行版中包含什么。而且我无权访问原始数据-我一直在压缩日志文件,所以我想找回它们。至于其他软件,我天真地尝试了7zip,但是当然失败了,因为它是zlib,而不是gzip(我无法使用任何软件直接解压缩zlib流)。我现在不能提供追溯的完整副本,但是它是(追溯到zlib.decompress(data))zlib.error:错误:-3。另外,需要明确的是,这些是静态文件,而不是我之前所说的流(因此没有传输错误)。而且我再次担心我没有代码,但是我知道我使用了zlib.compress(data,9)(即最高压缩级别-尽管有趣的是,似乎并非所有的zlib输出都是78da,因为您可能会期望,因为我将其置于最高级别),而只是zlib.decompress()。