web-dev-qa-db-ja.com

Pythonを使用して、大きなテキストファイルを小さなテキストファイルに行番号で分割する

テキストファイルに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を使用してこれを達成する最も簡単な方法についての提案をいただければ幸いです

24
walterfaye
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()
32
Matt Anderson

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=NoneNoneを確認するために各行を調べますが、発生すると、プロセスが完了したことを知っているので、jから1を差し引いて、フィラーを数え、ファイルに書き込みます。

24
jamylak
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()
3
Varun

私はこれをより理解できる方法で行い、これがどのようにそしてなぜ機能するかについてのさらなる理解を与えるために、より少ないショートカットを使用します。以前の答えは機能しますが、特定の組み込み関数に慣れていない場合は、その関数が何をしているのか理解できません。

あなたがコードを投稿しなかったので、基本的な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)
3
Ryan Saxe
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)
0
juliomalegria

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')
0
knowingpark