【问题标题】:Python gzip refuses to read uncompressed filePython gzip 拒绝读取未压缩的文件
【发布时间】:2013-05-29 11:58:12
【问题描述】:

我似乎记得 Python gzip 模块以前允许您透明地读取非 gzip 文件。这非常有用,因为它允许读取输入文件,无论它是否经过 gzip 压缩。您根本不必担心。

现在,我得到一个 IOError 异常(在 Python 2.7.5 中):

   Traceback (most recent call last):
  File "tst.py", line 14, in <module>
    rec = fd.readline()
  File "/sw/lib/python2.7/gzip.py", line 455, in readline
    c = self.read(readsize)
  File "/sw/lib/python2.7/gzip.py", line 261, in read
    self._read(readsize)
  File "/sw/lib/python2.7/gzip.py", line 296, in _read
    self._read_gzip_header()
  File "/sw/lib/python2.7/gzip.py", line 190, in _read_gzip_header
    raise IOError, 'Not a gzipped file'
IOError: Not a gzipped file

如果有人有巧妙的技巧,我很想听听。是的,我知道如何捕获异常,但是我发现先读取一行,然后关闭文件并再次打开它相当笨拙。

【问题讨论】:

  • 你确定你没记错吗?从 2.4 开始,我无法在任何版本中获得这种行为,并且由于 2.0! 之后的文档中没有提到这种行为!而且我也不希望 gzip 读取未压缩的文件。
  • 你不能直接打开文件,将它传递给 gzip,捕获异常,然后处理已经打开的文件吗?
  • 我想正确理解你。请不要冒犯。为什么要使用 gzip 打开未抓取的文件?对不起,但这对我来说毫无意义。请澄清您的问题。
  • 您希望为 gzip 或非 gzip 压缩数据使用通用打开器的原因是,如果您正在处理任意 gzip 或未 gzip 压缩的混合文件组。但是,滑坡问题是——如果你这样做,你会如何处理 bzip2 或 rar 文件或任何不属于 gzip/not-gzip 类别的文件),因为很多东西都不是压缩”。

标签: python gzip


【解决方案1】:

最好的解决方案是使用类似 https://github.com/ahupp/python-magic 的东西和 libmagic。您根本无法避免至少读取标头来识别文件(除非您隐式信任文件扩展名)

如果您感觉很简陋,那么识别 gzip(1) 文件的神奇数字是前两个字节是 0x1f 0x8b。

In [1]: f = open('foo.html.gz')
In [2]: print `f.read(2)`
'\x1f\x8b'

gzip.open 只是 GzipFile 的一个包装器,您可以使用这样的函数,根据源的内容返回正确的对象类型,而无需打开文件两次:

#!/usr/bin/python

import gzip

def opener(filename):
    f = open(filename,'rb')
    if (f.read(2) == '\x1f\x8b'):
        f.seek(0)
        return gzip.GzipFile(fileobj=f)
    else:
        f.seek(0)
        return f

【讨论】:

    【解决方案2】:

    也许您正在考虑 zless 或 zgrep,它们会打开压缩或未压缩的文件而不会产生任何问题。

    您能相信文件名以 .gz 结尾吗?

    if file_name.endswith('.gz'):
        opener = gzip.open
    else:
        opener = open
    
    with opener(file_name, 'r') as f:
        ...
    

    【讨论】:

    • mypy 不喜欢这样:“赋值中的类型不兼容(表达式具有类型重载函数,变量具有类型重载函数)”可能是因为github.com/python/mypy/issues/1026
    【解决方案3】:

    读取前四个字节。如果前三个是 0x1f、0x8b、0x08,并且如果第四个字节的高三位为零,则从这四个字节开始启动 gzip 压缩。否则写出这四个字节,继续透明读取。

    你应该仍然有笨重的解决方案来备份它,这样如果 gzip 读取仍然失败,那么备份并透明地读取。但是前四个字节不太可能很好地模仿 gzip 文件,但不是 gzip 文件。

    【讨论】:

      【解决方案4】:

      您可以使用 fileinput(files, openhook=fileinput.hook_compressed) 透明地迭代文件

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-07-06
        • 1970-01-01
        • 2013-11-16
        • 2014-07-04
        • 1970-01-01
        • 2017-01-19
        • 1970-01-01
        • 2010-10-12
        相关资源
        最近更新 更多