我正在编写一个脚本,它将使用来自仪器的数据作为gzip流.在大约90%的情况下,gzip模块工作得很好,但有些流导致它产生IOError: Not a gzipped file.如果删除gzip标头并将deflate流直接送入zlib,我会得到Error -3 while decompressing data: incorrect header check.在将我的头撞到墙上大约半天之后,我发现有问题的流包含一个看似随机数量的额外字节(不是gzip数据的一部分)附加到末尾.
令我感到奇怪的是Python无法使用这些文件有两个原因:
decompression OK, trailing garbage ignored,7zip默默地成功.)Gzip和Python文档似乎都表明这应该有用:(强调我的)
无论压缩数据的实际大小如何,都必须能够使用任何压缩方法检测压缩数据的结尾.特别是,解压缩器必须能够检测并跳过附加到面向记录的文件系统上的有效压缩文件的额外数据,或者当压缩数据只能以某个块大小的倍数从设备读取时.
调用
GzipFile对象的close()方法不会关闭fileobj,因为您可能希望在压缩数据之后附加更多材料.这也允许您将StringIO打开的对象作为fileobj传递,并使用StringIO对象的getvalue()方法检索生成的内存缓冲区.
Python的zlib.Decompress.unused_data:
一个字符串,包含压缩数据末尾之后的任何字节.也就是说,这一直存在,
""直到包含压缩数据的最后一个字节可用.如果整个字符串结果包含压缩数据,则为""空字符串.确定压缩数据字符串结束位置的唯一方法是实际解压缩它.这意味着当压缩数据包含在较大文件的一部分时,您只能通过读取数据并将其后跟一些非空字符串添加到解压缩对象的
decompress()方法中来找到它的结尾,直到该unused_data属性不再是空字符串.
以下是我尝试过的四种方法.(这些例子是Python 3.1,但我测试了2.5和2.7并且遇到了同样的问题.)
# approach 1 - gzip.open
with gzip.open(filename) as datafile:
data = datafile.read()
# approach 2 - gzip.GzipFile
with open(filename, "rb") as gzipfile:
with gzip.GzipFile(fileobj=gzipfile) as datafile:
data = datafile.read()
# approach 3 - zlib.decompress
with open(filename, "rb") as gzipfile:
data = zlib.decompress(gzipfile.read()[10:])
# approach 4 - zlib.decompressobj
with open(filename, "rb") as gzipfile:
decompressor = zlib.decompressobj()
data = decompressor.decompress(gzipfile.read()[10:])
Run Code Online (Sandbox Code Playgroud)
难道我做错了什么?
UPDATE
好吧,虽然问题gzip似乎是模块中的一个错误,但我的zlib问题是自己造成的.;-)
在挖掘时gzip.py我意识到我做错了什么 - 默认情况下,zlib.decompress等等.期待zlib包裹的流,而不是裸露的流.通过传递负值wbits,您可以告诉zlib跳过zlib标头并解压缩原始流.这两项工作:
# approach 5 - zlib.decompress with negative wbits
with open(filename, "rb") as gzipfile:
data = zlib.decompress(gzipfile.read()[10:], -zlib.MAX_WBITS)
# approach 6 - zlib.decompressobj with negative wbits
with open(filename, "rb") as gzipfile:
decompressor = zlib.decompressobj(-zlib.MAX_WBITS)
data = decompressor.decompress(gzipfile.read()[10:])
Run Code Online (Sandbox Code Playgroud)
Gle*_*ard 18
这是一个错误.Python中gzip模块的质量远远低于Python标准库中应该要求的质量.
这里的问题是gzip模块假定该文件是gzip格式文件流.在压缩数据的末尾,它从头开始,期待一个新的gzip头; 如果找不到,则引发异常.这是错的.
当然,连接两个gzip文件是有效的,例如:
echo testing > test.txt
gzip test.txt
cat test.txt.gz test.txt.gz > test2.txt.gz
zcat test2.txt.gz
# testing
# testing
Run Code Online (Sandbox Code Playgroud)
gzip模块的错误是,如果第二次没有gzip头,它不应该引发异常; 它应该只是结束文件.如果第一次没有标题,它应该只引发异常.
没有直接修改gzip模块就没有干净的解决方法; 如果你想这样做,请查看_read方法的底部.它应该设置另一个标志,例如.reading_second_block,告诉_read_gzip_header要提高EOFError而不是IOError.
此模块中还有其他错误.例如,它不必要地寻求,导致它在不可搜索的流(例如网络套接字)上失败.这让我对这个模块几乎没有信心:一个不知道gzip需要在没有搜索的情况下运行的开发人员非常不合格地为Python标准库实现它.
| 归档时间: |
|
| 查看次数: |
7956 次 |
| 最近记录: |