12

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

4

4 回答 4

35

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

  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.

“OK”使用 2,“bad”使用 3。因此,差异本身不是问题。

为了进一步了解,您可以考虑为每个压缩和(尝试)解压缩提供以下信息:什么平台,什么版本的 Python,什么版本的 zlib 库,用于调用 zlib 模块的实际代码是什么。还提供来自失败的解压缩尝试的完整回溯和错误消息。您是否尝试过使用任何其他 zlib 读取软件解压缩失败的文件?有什么结果?请澄清您必须处理的内容:“我被冲洗了吗?” 意味着您无权访问原始数据?它是如何从流到文件的?你有什么保证数据在传输中没有被破坏?

更新基于您的自我回答中发布的部分说明的一些观察:

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

压缩文件:

# 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()

解压文件:

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”,但在解压代码中没有使用[不太可能?],那么您并没有被淹没,您只需要充实上述解压代码并继续使用它。

请注意在以下未经测试的想法中使用“可能”、“应该”等。

如果您没有在压缩代码中使用 'rb' 和 'wb' ,那么您自己冲洗的可能性相当高。

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

如果 Ctrl-Z 是由 zlib 本身生成的,这应该会在尝试解压缩时导致早期 EOF,这当然会导致异常。在这种情况下,您可以通过以二进制模式读取压缩文件,然后将 '\r\n' 替换为 '\n' [即在没有 Ctrl-Z -> EOF 噱头的情况下模拟文本模式] 来小心地逆转该过程。解压结果。编辑在 TEXT 模式下写出结果。结束编辑

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

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'。

我可以用这个脚本恢复:

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('\r\n', '\n')
# (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”消息表明您尝试解压缩的数据自压缩以来已被破坏。如果不是在文件上使用文本模式引起的,那么怀疑显然(?)落在您的解密和加密包装器上。如果您需要帮助,您需要透露这些包装器的来源。实际上,您应该尝试做的是(就像我所做的那样)组合一个小脚本,该脚本可以在多个输入文件上重现问题。其次(像我一样)看看你是否可以在什么条件下扭转这个过程。如果您需要第二阶段的帮助,您需要泄露问题重现脚本。

于 2009-08-22T23:06:12.440 回答
4

我在寻找

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

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

于 2017-07-21T07:58:52.543 回答
-1

好吧,对不起我的上一篇文章,我没有一切。而且我无法编辑我的帖子,因为我没有使用 OpenID。无论如何,这里有一些数据:

1)解压回溯:

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

2)压缩代码:

#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) 解压代码:

f = open("somefile", 'rb')
data = f.read()
f.close()

zlib.decompress(decrypt(data)) #this yeilds the error in (1)
于 2009-08-23T20:28:24.660 回答
-1

好吧抱歉我不够清楚。这是win32,python 2.6.2。恐怕我找不到 zlib 文件,但它包含在 win32 二进制版本中的任何内容。而且我无权访问原始数据——我一直在压缩我的日志文件,我想取回它们。至于其他软件,我天真地尝试过 7zip,但当然失败了,因为它是 zlib,而不是 gzip(我无法使用任何软件直接解压缩 zlib 流)。我现在无法提供回溯的副本,但它是(回溯到 zlib.decompress(data))zlib.error: Error: -3。另外,需要明确的是,这些是静态文件,而不是我之前所说的流(所以没有传输错误)。而且我担心我没有代码,但我知道我使用了 zlib.compress(data, 9) (即在最高压缩级别 - 虽然,

于 2009-08-23T04:01:07.293 回答