为什么zlib.decompressobj解压成功但zlib.decompress会失败?
zlib.decompressobj与zlib.decompress解压行为差异说明
问题复现
你提供的测试代码如下:
import zlib data = b'x\x9c4\xc9A\x0e\x820\x10\x05\xd0\xbb\xfcuK\x8a\xe8f\xaeB\t\x19`\x82MJ!\xed\xa81M\xef\xae\x1bw/y\x15\nJ\xcf\x18\r\xca\x1f\xc7\t\xea\x9c\xc1\n\xaax\x08g\x9d\x85u\nI%\xbf8\x82n\xdd\xf5\xfe\xfbI3/\x02\x1a0xl\xac\xf2\xe6\x8f=\xf3jw\x0e\xc9\xf6E7\x0fS=\xf6\xb0\xe4\xa3x\x90\xbb\xb86bl\xed\x0b\x00\x00\xff\xff' result = zlib.decompressobj().decompress(data) print(result) result2 = zlib.decompress(data) print(result2)
运行后decompressobj成功返回解压后的JSON片段,decompress抛出zlib.error: Error -5 while decompressing data: incomplete or truncated stream错误。
根本原因
两个接口的设计定位完全不同:
zlib.decompress是一次性完整解压接口,要求输入的压缩数据必须是完整的zlib格式数据流,包含标准头部、压缩内容、尾部Adler32校验和,只要检测到数据流不完整就会直接抛出异常,不会返回已解压的部分内容。zlib.decompressobj是流式解压接口,设计用来应对压缩数据分片到达的场景,调用decompress方法时会尽可能解析当前输入块中所有可识别的压缩内容,哪怕数据流没有结束、缺少尾部校验,也会返回已经解压成功的内容,只有遇到格式非法的内容才会抛出异常。
你提供的测试用压缩数据恰好是截断的,缺少尾部4字节的Adler32校验和,因此触发了两个接口的行为差异。
修复方案
如果需要用zlib.decompress处理截断的压缩流,可以从捕获的异常中提取已解压的内容:
import zlib data = b'x\x9c4\xc9A\x0e\x820\x10\x05\xd0\xbb\xfcuK\x8a\xe8f\xaeB\t\x19`\x82MJ!\xed\xa81M\xef\xae\x1bw/y\x15\nJ\xcf\x18\r\xca\x1f\xc7\t\xea\x9c\xc1\n\xaax\x08g\x9d\x85u\nI%\xbf8\x82n\xdd\xf5\xfe\xfbI3/\x02\x1a0xl\xac\xf2\xe6\x8f=\xf3jw\x0e\xc9\xf6E7\x0fS=\xf6\xb0\xe4\xa3x\x90\xbb\xb86bl\xed\x0b\x00\x00\xff\xff' try: result2 = zlib.decompress(data) except zlib.error as e: # 截断错误的异常对象第二个参数就是已解压完成的内容 if e.args[0] == -5: result2 = e.args[1] print(result2)
运行后得到的结果和decompressobj返回的内容完全一致。
内容的提问来源于stack exchange,提问作者Kvothe
相关产品推荐
相关产品推荐

