2016-03-15 103 views
6

我有大的gzip壓縮文件。 我寫了一段代碼將這些文件拆分爲更小的文件。我可以指定 每個文件的行數。最近的事情是,我最近將每個分割線 的行數增加到了16,000,000,並且當我處理更大的文件時,分割不會發生。有時會生成較小的文件 ,有時會生成一個但重量僅爲40B或50B,即 失敗。我試圖通過查看gzip 代碼中引發的異常來捕捉異常。所以,我的代碼如下所示:gzip在寫入文件中的大量數據時失敗

def writeGzipFile(file_name, content): 
    import gzip 
    with gzip.open(file_name, 'wb') as f: 
     if not content == '': 
      try: 
       f.write(content) 
      except IOError as ioe: 
       print "I/O ERROR wb", ioe.message 
      except ValueError as ve: 
       print "VALUE ERROR wb: ", ve.message 
      except EOFError as eofe: 
       print "EOF ERROR wb: ", eofe.message 
      except: 
       print "UNEXPECTED ERROR wb" 

的事情是,當含量過高,涉及的行數,我經常得到 「意外的錯誤」的消息。所以我不知道在這裏拋出哪種錯誤。

我終於發現行數是問題,並且它看起來python的gzip在一次寫入一個文件中的數據量時失敗。將每個分割線的數量降低至4,000,000個作品。不過,我想分割內容並按順序寫入文件,以確保寫入甚至是高數據內容。

所以我想知道如何找出在文件中一次性使用gzip而沒有任何失敗的情況下可以寫入的最大字符數。


編輯1

所以我caugth所有剩餘異常(我不知道這是可以簡單地趕上Exception不好意思):

def writeGzipFile(file_name, content, file_permission=None): 
    import gzip, traceback 
    with gzip.open(file_name, 'wb') as f: 
     if not content == '': 
      try: 
       f.write(content) 
      except IOError as ioe: 
       print "I/O ERROR wb", ioe.message 
      except ValueError as ve: 
       print "VALUE ERROR wb: ", ve.message 
      except EOFError as eofe: 
       print "EOF ERROR wb: ", eofe.message 
      except Exception, err: 
       print "EXCEPTION:", err.message 
       print "TRACEBACK_1:", traceback.print_exc(file=sys.stdout) 
      except: 
       print "UNEXPECTED ERROR wb" 

的誤差約爲int大小。我從來沒有想過我會超過INT尺寸第一天:

EXCEPTION: size does not fit in an int 
TRACEBACK_1:Traceback (most recent call last): 
    File "/home/anadin/dev/illumina-project-restructor_mass-splitting/illumina-project-restructor/tools/file_utils/file_compression.py", line 131, in writeGzipFile 
    f.write(content) 
    File "/usr/local/cluster/python2.7/lib/python2.7/gzip.py", line 230, in write 
    self.crc = zlib.crc32(data, self.crc) & 0xffffffffL 
OverflowError: size does not fit in an int 
None 

好了,所以int的最大大小爲2,147,483,647,我的數據塊是約3854674090根據我的日誌。這個塊是我應用__len__()函數的一個字符串。

因此,正如我計劃要做的那樣,正如Antti Haapala所建議的那樣,我將一次讀取更小的塊,以便按順序將它們寫入較小的文件。

+1

當您解決此問題時,請回答 - *不要使用未命名的異常塊* - 因爲它們通過隱藏失敗機制導致這類問題。 (除非你真的*不在乎操作失敗)。 – SiHa

+1

如果它在你處理的數據量減少的情況下起作用,那麼我很確定問題在於你將所有數據放在一個字符串中:'content'。這可能會耗盡你所有的記憶。我沒有看到代碼的其餘部分,但通常你需要讀取一小塊數據(通常是一行代碼),隨意使用它,然後將其提供給gzip,然後將該小塊寫入磁盤。然後你重複這1600萬次(或者經常),並且在任何時候,佔用的內存都不會超過單行...... – Carpetsmoker

+0

FWIW,[this answer](http://stackoverflow.com/a/27037303/ 4014959)我在幾年前寫了一個演示如何逐個塊地分塊文件。 –

回答

5

無論如何,我懷疑原因是某種內存不足的錯誤。我很不清楚爲什麼你一次不寫這些數據的次數較少;這裏使用chunks方法from this answer

def chunks(l, n): 
    """Yield successive n-sized chunks from l.""" 
    for i in xrange(0, len(l), n): 
     yield l[i:i+n] 

... 
with gzip.open(file_name, 'wb') as f: 
    for chunk in chunks(content, 65536): 
     f.write(chunk) 

也就是說,你做這樣你會吃掉一頭大象,採取一咬一次。

+0

謝謝我的問題有點複雜,但原則是一次只寫更小的塊。順便說一句,爲什麼你將塊限制在65536?在這裏我受限於int尺寸。我可以用int範圍替換你的尺寸嗎?或者更有效率的東西,你拿什麼? – kaligne

+0

我仍然不會嘗試我的運氣!你會更快地用完內存。這種拼接實際上*複製了一部分字符串。 –

+0

@ kaligne:64k是一個很好的塊大小。根據您的硬件,您*可能會獲得稍微更快的性能,而且塊大小會有所不同,但是IME的改進是非常小的,並且我已經對一系列驅動器(包括機械和固態)進行了測試。請記住,您不直接與硬件進行連接,而是通過使用高效磁盤緩衝的操作系統驅動程序軟件,並且驅動器也擁有自己的板載高速緩存。 –