如何用Python读取没有头部或MIME类型的Gzip字符串?

2 投票
1 回答
4488 浏览
提问于 2025-04-17 12:19

我有一个经过压缩的字符串,它是从另一个应用程序创建并存储的。现在我拿到了这个字符串(没有任何文件类型或头信息),我需要把它解压缩。

有没有办法在Python中做到这一点呢?

[编辑] 为了测试,我直接把这个字符串复制粘贴到记事本里,然后把文件重命名为 .gz。我还尝试过把字符串直接粘贴到IDLE里。

我看到的其他例子都假设有文件类型和文件头信息,而我只有一个大字符串。

使用 zlib.decompress(mystring) 会出现错误 Error -3 while decompressing data: incorrect header check

1 个回答

1

确认一下@reclosedev的评论,并补充一些内容:

]后面的字节需要进行base64解码。

解码后,会得到4个字节,这4个字节表示解压后数据的长度,采用的是32位小端二进制格式。剩下的部分是符合RFC-1952标准的gzip流,能够通过开头的1F 8B 08来识别。解压后的结果看起来像是二进制数据,而不是ASCII的1和0字符串。

代码:

lines = [
    # extracted from the linked csv file 
    "[133,120,696,286]MmEAAB+LCAAAAAAABADtvQdg [BIG snip] a0bokyYQAA",
    "[73,65,564,263]bkgAAB+LCAAAAAAABADtvQdgHE [BIG snip] kgAAA==",
    ]
import zlib, struct
for line in lines:
    print
    b64 = line.split(']')[1]
    raw = b64.decode('base64')
    print "unknown:", repr(raw[:4])
    print "unknown as 32-bit LE int:", struct.unpack("<I", raw[:4])[0]
    ungz = zlib.decompress(raw[4:], 31)
    print len(ungz), "bytes in decompressed data"
    print "first 100:", repr(ungz[:100])

输出:

unknown: '2a\x00\x00'
unknown as 32-bit LE int: 24882
24882 bytes in decompressed data
first 100: '\xff\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xf0\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00'

unknown: 'nH\x00\x00'
unknown as 32-bit LE int: 18542
18542 bytes in decompressed data
first 100: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f\xff\xff\xff\xff
\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x07\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x80
\x00\x00\x00'

更新:根据评论的反馈

为了得到我需要的1和0,我只是把这个加到上面
cleaned = bin(int(binascii.hexlify(ungz), 16))

“只是”?你还需要把前面的'0b'去掉,然后在前面加上足够的零,使得总长度是8的倍数。比如,使用更好的方法:

>>> import binascii
>>> ungz = '\x01\x80'
>>> bin(int(binascii.hexlify(ungz), 16))
'0b110000000'
>>> ''.join('{0:08b}'.format(ord(x)) for x in ungz)
'0000000110000000'

你有没有仔细检查,确保你真的想要'0000000110000000'而不是'1000000000000001'

撰写回答