2013-05-29 43 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: 
    ...