Pythonを使用して大きなファイルを分割する

Split large files using python


質問 written by LookIntoEast @2011-11-11 15:58:50Z

: 9 : 5 : 16

大きなファイル(たとえば、約10GB)を分割しようとすると、いくつかの問題が発生します。 基本的な考え方は、単に行を読み取り、40000行ごとに1つのファイルにグループ化することです。 ただし、ファイルを「読み取る」方法は2つあります。

1)最初の方法は、WHOLEファイルを一度に読み取り、リストにすることです。 ただし、これにはWHOLEファイルをメモリにロードする必要がありますが、これは大きすぎるファイルには苦痛です。 (私は前にそのような質問をしたと思います)pythonでは、一度に私が試した完全なファイルを読み取るためのアプローチは次のとおりです:

input1=f.readlines()

input1 = commands.getoutput('zcat ' + file).splitlines(True)

input1 = subprocess.Popen(["cat",file],
                              stdout=subprocess.PIPE,bufsize=1)

それでは、40000行をlist[40000,80000] or list[80000,120000]簡単に1つのファイルにグループ化できますlist[40000,80000] or list[80000,120000]または、リストを使用する利点は、特定の行を簡単にポイントできることです。

2)2番目の方法は、行ごとに読み取ることです。 行を読み込むときに処理します。 これらの読み取り行はメモリに保存されません。 例は次のとおりです。

f=gzip.open(file)
for line in f: blablabla...

または

for line in fileinput.FileInput(fileName):

gzip.openの場合、このfはリストではなく、ファイルオブジェクトです。 そして、行ごとにしか処理できないようです。 次に、この「分割」ジョブを実行するにはどうすればよいですか? ファイルオブジェクトの特定の行をポイントするにはどうすればよいですか?

ありがとう

コメント 1

考えてみると、できません。前の行をすべて読み、改行を数えた(\ n)後にのみ、どの行にいるのかを知ることができます。(これは、各行の長さが既知の奇妙なファイルであるという特殊なケースを無視します。)

written by rplnt @2011-11-11 16:05:32Z

回答 1 written by yurib @2017-01-23 16:01:32Z
15
NUM_OF_LINES=40000
filename = 'myinput.txt'
with open(filename) as fin:
    fout = open("output0.txt","wb")
    for i,line in enumerate(fin):
      fout.write(line)
      if (i+1)%NUM_OF_LINES == 0:
        fout.close()
        fout = open("output%d.txt"%(i/NUM_OF_LINES+1),"wb")

    fout.close()
コメント 1

ファイルに正確に40,000行が必要な場合は、 i0ではなく0に初期化する必要があると思います。

written by マルティノー @2011-11-11 16:27:23Z

コメント 2

なぜfileinputを使用するのですか?

written by ジョンマシン @2011-11-11 19:15:00Z

コメント 3

どのパッケージが必要ですか?

written by ルイスフェリペ @2017-01-23 15:39:58Z

コメント 4

@LuisFelipe外部パッケージは必要ありません。fileinputは組み込みパッケージであり、この機能には必要ありません。プレーンなopen()使用することもできます

written by yurib @2017-01-23 15:50:39Z

コメント 5

@LuisFelipe filenameは、入力ファイルへのパスを含む必要がある変数です

written by -yurib @2017-01-23 15:53:39Z

回答 2 written by bgporter @2011-11-13 17:54:57Z
4

各ファイルに特定の行数のファイルをreadlines()ことについて特別なものがない場合、 readlines()関数は、次のように動作するサイズ「ヒント」パラメーターも受け入れます。

オプションのパラメーターsizehintが指定されている場合、ファイルからそのバイト数を読み取り、さらに行を完了するのに十分なバイト数を読み取り、その行を返します。 これは、ファイル全体をメモリにロードすることなく、大きなファイルを行単位で効率的に読み取るためによく使用されます。 完全な行のみが返されます。

...そのため、次のようなコードを記述できます。

# assume that an average line is about 80 chars long, and that we want about 
# 40K in each file.

SIZE_HINT = 80 * 40000

fileNumber = 0
with open("inputFile.txt", "rt") as f:
   while True:
      buf = f.readlines(SIZE_HINT)
      if not buf:
         # we've read the entire file in, so we're done.
         break
      outFile = open("outFile%d.txt" % fileNumber, "wt")
      outFile.write(buf)
      outFile.close()
      fileNumber += 1 
コメント 1

-1(1)出力ファイルを明示的に閉じない(2)テキストモードでの読み取りとバイナリモードでの書き込みは、「Windowsを使用している場合に物事を壊す」ことを保証されています。

written by @

コメント 2

(3) fileNumber += 1インデントが正しくありませfileNumber += 1

written by Machin @2011-11-11 20:11:30Z

コメント 3

@JohnMachin正しいX3。ずさんなところを見つけてくれてありがとう。

written by -bgporter @2011-11-13 17:55:19Z

回答 3 written by Jason Sundram @2011-11-11 19:23:53Z
3
chunk_size = 40000
fout = None
for (i, line) in enumerate(fileinput.FileInput(filename)):
    if i % chunk_size == 0:
        if fout: fout.close()
        fout = open('output%d.txt' % (i/chunk_size), 'w')
    fout.write(line)
fout.close()
コメント 1

if fout: fout.close()を行う必要がありますif fout: fout.close()ループを終了した後にif fout: fout.close()

written by ジョンマシン @2011-11-11 19:18:33Z

コメント 2

ありがとう、@ JohnMachin。一定。

written by ジェイソンスンドラム @2011-11-11 19:24:21Z

回答 4 written by NPE @2011-11-11 16:07:38Z
2

10GBファイルの場合、2番目のアプローチは明らかに進むべき方法です。 必要なことの概要は次のとおりです。

  1. 入力ファイルを開きます。
  2. 最初の出力ファイルを開きます。
  3. 入力ファイルから1行を読み取り、出力ファイルに書き込みます。
  4. 現在の出力ファイルに書き込んだ行数のカウントを維持します。 40000に達したらすぐに、出力ファイルを閉じて、次のファイルを開きます。
  5. 入力ファイルの最後に到達するまで、手順3〜4を繰り返します。
  6. 両方のファイルを閉じます。
コメント 1

if num_lines % 4000 == 0: avoid_writing_empty_file_at_end() # except when numlines == 0

written by Machin @2011-11-11 19:10:48Z

回答 5 written by Josh Imhoff @2011-11-11 17:24:25Z
0

明らかに、ファイルで作業しているときに、何らかの方法でファイルの内容を反復処理する必要があります-それを手動で行うか、Python APIの一部にあなたに代わってさせるか(例えば、readlines()メソッド) ) 重要ではありません。 ビッグO分析では、これはO(n)時間を費やすことを意味します(nはファイルのサイズです)。

ただし、ファイルをメモリに読み込むには、O(n)スペースも必要です。 10 GBのファイルをメモリに読み込む必要がある場合もありますが、特定の問題ではこれを必要としません。 ファイルオブジェクトを直接反復処理できます。 もちろん、ファイルオブジェクトにはスペースが必要ですが、ファイルの内容を2つの異なる形式で2回保持する理由はありません。

したがって、私はあなたの2番目の解決策に行きます。