itertools
ハタのレシピを使用:
from itertools import zip_longest
def grouper(n, iterable, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx
args = [iter(iterable)] * n
return zip_longest(fillvalue=fillvalue, *args)
n = 300
with open('really_big_file.txt') as f:
for i, g in enumerate(grouper(n, f, fillvalue=''), 1):
with open('small_file_{0}'.format(i * n), 'w') as fout:
fout.writelines(g)
各行をリストに保存するのとは対照的に、この方法の利点は、イテラブルを行ごとに処理するため、それぞれsmall_file
を一度にメモリに保存する必要がないことです。
この場合の最後のファイルは になりますsmall_file_100200
が、までしかないことに注意してくださいline 100000
。これは、グループ サイズが均等に分割されないため、書き込む行が残っていないときに、ファイルに何もfillvalue=''
書き出さないために発生します。私のように最初に名前を付けるのではなく、一時ファイルに書き込んでから名前を変更することで、これを修正できます。これを行う方法は次のとおりです。
import os, tempfile
with open('really_big_file.txt') as f:
for i, g in enumerate(grouper(n, f, fillvalue=None)):
with tempfile.NamedTemporaryFile('w', delete=False) as fout:
for j, line in enumerate(g, 1): # count number of lines in group
if line is None:
j -= 1 # don't count this line
break
fout.write(line)
os.rename(fout.name, 'small_file_{0}.txt'.format(i * n + j))
今回はfillvalue=None
と各行を調べて をチェックしNone
ます。それが発生すると、プロセスが終了したことがわかっているので、フィラーをカウントしないように1
から減算してからファイルを書き込みます。j