2017-04-10 81 views
4

比方說,我只有8G的可用堆空間,並且我想將比這更大的文件轉換爲一系列較小的文件。如果我嘗試如何拆分大於內存大小的文件?

with open(fname) as f: 
    content = f.readlines() 

我將耗盡內存,因爲它會嘗試加載整個文件。有沒有辦法打開文件,而無需在內存中加載整個文件,只需要從X到Y?

+1

迭代f而不是用readlines()讀取整個文件 – jordanm

+1

這種情況下每個迭代單元是什麼? – amphibient

+0

這可能是一個重複:http://stackoverflow.com/questions/2363483/python-slicing-a-very-large-binary-file –

回答

1

itertools.islice是工作的好工具,但你需要考慮如何有效地使用它。例如,islice(f, 10, 20)丟棄10行然後發出20行,因此這不是寫入的好方法。根據您編寫循環的方式,您可以刪除數據或重新掃描每次寫入的文件。

它也不是很明顯知道你什麼時候完成。 fileobj.writelines(isslice(f, 10))會愉快地寫0行文件直到時間結束。你真的只知道你是在事實之後完成的,所以你可以測試你是否寫了一個零長度的文件來終止。

在這個例子中,我的大文件是100行長,我分成10行apeice ....這比8gig文件測試有點快。

import itertools 
import os 

lines_per_file = 10 

with open('big.txt') as infp: 
    # file counter used to create unique output files 
    for file_count in itertools.count(1): 
     out_filename = 'out-{}.txt'.format(file_count) 
     with open(out_filename, 'w') as outfp: 
      # write configured number of lines to file 
      outfp.writelines(itertools.islice(infp, lines_per_file)) 
     # break when no extra data written 
     if os.stat(out_filename).st_size == 0: 
      os.remove(out_filename) 
      break 
+0

RE:「知道你何時完成並不明顯」 - 正是我爲什麼要對其他答案發表評論「我怎麼知道我何時到達EOF?」 – amphibient

2

文件句柄可以用作文件中行的迭代器。你想要的是來自該迭代器的特定切片。在標準庫中有一個方便的itertools.islice()函數可以完成這個功能。

from itertools import islice 

line_slice = (10, 20) 
with open(fname) as f: 
    content = islice(f, *line_slice) 

上面的內容或多或少相當於f.readlines()[10:20]

請注意,islice()的輸出是另一個迭代器。幸運的是writelines()接受迭代器,所以不需要將其轉換爲臨時列表。這也意味着,如果您直接將其傳遞給writelines(),則在任何時候都不會在內存中保留多行內容。

with open(out_fname, 'w') as f: 
    f.writelines(content) 
+0

你能寫一個簡短的方法和參數的描述嗎? –

+0

該方法看起來不錯,但是,如何知道何時到達EOF?它不會拋出異常 – amphibient