2013-05-29 44 views
4

我似乎记得Python gzip模块以前允许您透明地读取非gzip文件。这非常有用,因为它允许读取输入文件,而不管它是否被压缩。你根本不必担心。Python 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 

如果任何人有一个巧妙的方法,我想听到它。是的,我知道如何捕捉这个异常,但是我发现它首先读取一行,然后关闭文件并再次打开,这相当笨拙。

+1

你肯定你记错遍历文件?我无法从2.4的任何版本中获得该行为,并且从[2.0](http://docs.python.org/2.0/lib/module-gzip.html)开始,文档中没有提及此行为!我永远不会希望gzip能够读取未压缩的文件。 – mata

+1

难道你不能只打开文件,将它传递给gzip,捕获异常,然后使用已打开的文件? – Mezgrman

+0

我想理解你的权利。请不要冒犯。你为什么要用gzip打开一个没有抓住的文件?对不起,但对我来说没有意义。请澄清你的问题。 – PSS

回答

8

最好的解决方案是使用类似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 
1

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

您应该仍然有笨重的解决方案来支持它,所以如果gzip读取失败,然后备份并透明地读取。但前四个字节应该不太可能模仿gzip文件,但不能成为gzip文件。

4

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

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

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

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