Python gzip拒绝读取未压缩的文件

18

我似乎记得 Python gzip 模块之前允许你在不解压的情况下透明地读取非gzip文件,这非常有用,因为它可以让你无论输入文件是否被gzip都能够读取。你根本不需要担心它。

现在,在 Python 2.7.5 中,我会收到一个 IOError 异常:

   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
你确定你记得没错吗?我无法在任何2.4版本中获得那种行为,而且自从2.0以来文档中也没有提到过这种行为!而且我也不会期望gzip读取未压缩的文件。 - mata
2
你不能只是打开文件,将其传给gzip,捕获异常,然后继续使用已经打开的文件吗? - Mezgrman
我尝试理解你的意思。请不要生气。为什么你想要使用gzip来打开一个没有被压缩的文件呢?对我来说没有道理。请澄清你的问题。 - PSS
3
如果你需要处理一组混合的文件,这些文件可能是任意的gzip或非gzip格式,那么你会希望有一个通用的gzip打开器。但问题是,如果你遇到了bzip2、rar或其他不属于gzip/非gzip类别的文件,怎么办呢?因为很多文件并不是gzip格式的。 - synthesizerpatel
4个回答

14
这个问题的最佳解决方案是使用类似于 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的包装器,你可以编写一个类似这样的函数,根据源的不同只返回正确类型的对象,而无需打开文件两次:

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

10

也许你在想zless或zgrep,它们会打开压缩或未压缩的文件而不会抱怨。

你能相信文件名以“.gz”结尾吗?

if file_name.endswith('.gz'):
    opener = gzip.open
else:
    opener = open

with opener(file_name, 'r') as f:
    ...

mypy 不喜欢这个: "在赋值时类型不兼容 (表达式的类型为 overloaded function,变量的类型为 overloaded function)" 可能是因为 https://github.com/python/mypy/issues/1026。 - Johan Walles

2
读取前四个字节。如果前三个字节是0x1f、0x8b、0x08,且第四个字节的高三位为零,则启动gzip压缩并从这四个字节开始。否则,写出这四个字节并继续透明地读取。
您仍然应该有笨重的解决方案来支持它,以便如果gzip读取失败,那么可以回退并透明地读取。但是,很不可能前四个字节如此完美地模仿gzip文件,却不是gzip文件。

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接