テキストファイルにreally_big_file.txtと書いてあります。
line 1
line 2
line 3
line 4
...
line 99999
line 100000
Pythonスクリプトを作成して、really_big_file.txtをそれぞれ300行の小さなファイルに分割します。たとえば、small_file_300.txtは1〜300行、small_file_600は301〜600行です。 、というように、大きなファイルのすべての行を含めるために作成された十分な小さなファイルができるまで続きます。
Pythonを使用してこれを達成する最も簡単な方法についての提案をいただければ幸いです
lines_per_file = 300
smallfile = None
with open('really_big_file.txt') as bigfile:
for lineno, line in enumerate(bigfile):
if lineno % lines_per_file == 0:
if smallfile:
smallfile.close()
small_filename = 'small_file_{}.txt'.format(lineno + lines_per_file)
smallfile = open(small_filename, "w")
smallfile.write(line)
if smallfile:
smallfile.close()
itertools
grouper レシピを使用:
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)
リストに各行を格納するのではなく、このメソッドの利点は、イテラブルを1行ずつ処理するため、各small_file
を一度にメモリに格納する必要がないことです。
この場合の最後のファイルはsmall_file_100200
になりますが、line 100000
までしか移動しないことに注意してください。これは、fillvalue=''
、つまりグループが原因で書き込む行が残っていないときに、ファイルにnothingを書き込むために発生します。サイズは均等に分割されません。これを修正するには、一時ファイルに書き込み、名前を最初に付けるのではなく、後で名前を変更します。これを行う方法は次のとおりです。
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
を確認するために各行を調べますが、発生すると、プロセスが完了したことを知っているので、j
から1
を差し引いて、フィラーを数え、ファイルに書き込みます。
import csv
import os
import re
MAX_CHUNKS = 300
def writeRow(idr, row):
with open("file_%d.csv" % idr, 'ab') as file:
writer = csv.writer(file, delimiter=',', quotechar='\"', quoting=csv.QUOTE_ALL)
writer.writerow(row)
def cleanup():
for f in os.listdir("."):
if re.search("file_.*", f):
os.remove(os.path.join(".", f))
def main():
cleanup()
with open("large_file.csv", 'rb') as results:
r = csv.reader(results, delimiter=',', quotechar='\"')
idr = 1
for i, x in enumerate(r):
temp = i + 1
if not (temp % (MAX_CHUNKS + 1)):
idr += 1
writeRow(idr, x)
if __name__ == "__main__": main()
私はこれをより理解できる方法で行い、これがどのようにそしてなぜ機能するかについてのさらなる理解を与えるために、より少ないショートカットを使用します。以前の答えは機能しますが、特定の組み込み関数に慣れていない場合は、その関数が何をしているのか理解できません。
あなたがコードを投稿しなかったので、基本的なpython構文以外の構文に慣れていない可能性があるので、この方法で行うことにしました。質問へのアプローチ方法についての手がかりもなかった
基本的なpythonでこれを行う手順は次のとおりです。
最初に、保管のためにファイルをリストに読み込む必要があります。
my_file = 'really_big_file.txt'
hold_lines = []
with open(my_file,'r') as text_file:
for row in text_file:
hold_lines.append(row)
次に、新しいファイルを名前で作成する方法を設定する必要があります。私はいくつかのカウンターと一緒にループを提案します:
outer_count = 1
line_count = 0
sorting = True
while sorting:
count = 0
increment = (outer_count-1) * 300
left = len(hold_lines) - increment
file_name = "small_file_" + str(outer_count * 300) + ".txt"
3番目に、そのループ内では、正しい行を配列に保存するいくつかのネストされたループが必要です。
hold_new_lines = []
if left < 300:
while count < left:
hold_new_lines.append(hold_lines[line_count])
count += 1
line_count += 1
sorting = False
else:
while count < 300:
hold_new_lines.append(hold_lines[line_count])
count += 1
line_count += 1
最後に、最初のループでも、新しいファイルを書き込み、最後のカウンターの増分を追加して、ループが再び実行されて新しいファイルを書き込むようにする必要があります。
outer_count += 1
with open(file_name,'w') as next_file:
for row in hold_new_lines:
next_file.write(row)
注:行数が300で割り切れない場合、最後のファイルには、最後のファイル行に対応しない名前が付けられます。
これらのループが機能する理由を理解することが重要です。次のループで、変更する変数に依存する名前を持つため、書き込むファイルの名前が変更されるように設定します。これは、ファイルのアクセス、オープン、書き込み、整理などのための非常に便利なスクリプトツールです。
ループの内容を追跡できない場合のために、関数全体を次に示します。
my_file = 'really_big_file.txt'
sorting = True
hold_lines = []
with open(my_file,'r') as text_file:
for row in text_file:
hold_lines.append(row)
outer_count = 1
line_count = 0
while sorting:
count = 0
increment = (outer_count-1) * 300
left = len(hold_lines) - increment
file_name = "small_file_" + str(outer_count * 300) + ".txt"
hold_new_lines = []
if left < 300:
while count < left:
hold_new_lines.append(hold_lines[line_count])
count += 1
line_count += 1
sorting = False
else:
while count < 300:
hold_new_lines.append(hold_lines[line_count])
count += 1
line_count += 1
outer_count += 1
with open(file_name,'w') as next_file:
for row in hold_new_lines:
next_file.write(row)
lines_per_file = 300 # Lines on each small file
lines = [] # Stores lines not yet written on a small file
lines_counter = 0 # Same as len(lines)
created_files = 0 # Counting how many small files have been created
with open('really_big_file.txt') as big_file:
for line in big_file: # Go throught the whole big file
lines.append(line)
lines_counter += 1
if lines_counter == lines_per_file:
idx = lines_per_file * (created_files + 1)
with open('small_file_%s.txt' % idx, 'w') as small_file:
# Write all lines on small file
small_file.write('\n'.join(stored_lines))
lines = [] # Reset variables
lines_counter = 0
created_files += 1 # One more small file has been created
# After for-loop has finished
if lines_counter: # There are still some lines not written on a file?
idx = lines_per_file * (created_files + 1)
with open('small_file_%s.txt' % idx, 'w') as small_file:
# Write them on a last small file
small_file.write('n'.join(stored_lines))
created_files += 1
print '%s small files (with %s lines each) were created.' % (created_files,
lines_per_file)
650000行のファイルでも同じことをしなければなりませんでした。
列挙インデックスと整数divを使用して(//)チャンクサイズで
その番号が変更されると、現在のファイルを閉じて新しいファイルを開きます
これは、フォーマット文字列を使用するpython3ソリューションです。
chunk = 50000 # number of lines from the big file to put in small file
this_small_file = open('./a_folder/0', 'a')
with open('massive_web_log_file') as file_to_read:
for i, line in enumerate(file_to_read.readlines()):
file_name = f'./a_folder/{i // chunk}'
print(i, file_name) # a bit of feedback that slows the process down a
if file_name == this_small_file.name:
this_small_file.write(line)
else:
this_small_file.write(line)
this_small_file.close()
this_small_file = open(f'{file_name}', 'a')