ディレクトリ内のすべてのファイルを1つのファイルに連結する次のスクリプトを作成しました。
これを最適化できますか
慣用的なpython
時間
これがスニペットです:
import time, glob
outfilename = 'all_' + str((int(time.time()))) + ".txt"
filenames = glob.glob('*.txt')
with open(outfilename, 'wb') as outfile:
for fname in filenames:
with open(fname, 'r') as readfile:
infile = readfile.read()
for line in infile:
outfile.write(line)
outfile.write("\n\n")
_shutil.copyfileobj
_ を使用してデータをコピーします。
_import shutil
with open(outfilename, 'wb') as outfile:
for filename in glob.glob('*.txt'):
if filename == outfilename:
# don't want to copy the output into the output
continue
with open(filename, 'rb') as readfile:
shutil.copyfileobj(readfile, outfile)
_
shutil
は、readfile
オブジェクトをチャンクで読み取り、outfile
ファイルオブジェクトに直接書き込みます。行末を見つけるオーバーヘッドが必要ないため、readline()
または反復バッファーを使用しないでください。
読み取りと書き込みの両方に同じモードを使用します。これは、Python 3を使用する場合に特に重要です。ここでは両方にバイナリモードを使用しました。
Python 2.7を使用して、いくつかの「ベンチマーク」テストを行いました
outfile.write(infile.read())
対
shutil.copyfileobj(readfile, outfile)
私は、サイズが63 MBから313 MBまでの.txtファイルを20個以上繰り返し、結合ファイルのサイズは〜2.6 GBでした。どちらの方法でも、通常の読み取りモードはバイナリ読み取りモードよりもパフォーマンスが高く、shutil.copyfileobjは一般にoutfile.writeよりも高速でした。
最悪の組み合わせ(outfile.write、バイナリモード)と最適な組み合わせ(shutil.copyfileobj、通常の読み取りモード)を比較すると、その違いは非常に大きくなります。
outfile.write, binary mode: 43 seconds, on average.
shutil.copyfileobj, normal mode: 27 seconds, on average.
出力ファイルの最終サイズは、通常の読み取りモードでは2620 MB、バイナリ読み取りモードでは2578 MBでした。
それほど多くの変数を使用する必要はありません。
with open(outfilename, 'w') as outfile:
for fname in filenames:
with open(fname, 'r') as readfile:
outfile.write(readfile.read() + "\n\n")
fileinput モジュールは、複数のファイルを反復する自然な方法を提供します
for line in fileinput.input(glob.glob("*.txt")):
outfile.write(line)
パフォーマンスの詳細を確認したいので、Martijn PietersとStephen Millerの回答を使用しました。
shutil
あり、shutil
なしのバイナリモードとテキストモードを試しました。 270個のファイルをマージしてみました。
テキストモード-
def using_shutil_text(outfilename):
with open(outfilename, 'w') as outfile:
for filename in glob.glob('*.txt'):
if filename == outfilename:
# don't want to copy the output into the output
continue
with open(filename, 'r') as readfile:
shutil.copyfileobj(readfile, outfile)
def without_shutil_text(outfilename):
with open(outfilename, 'w') as outfile:
for filename in glob.glob('*.txt'):
if filename == outfilename:
# don't want to copy the output into the output
continue
with open(filename, 'r') as readfile:
outfile.write(readfile.read())
バイナリモード-
def using_shutil_text(outfilename):
with open(outfilename, 'wb') as outfile:
for filename in glob.glob('*.txt'):
if filename == outfilename:
# don't want to copy the output into the output
continue
with open(filename, 'rb') as readfile:
shutil.copyfileobj(readfile, outfile)
def without_shutil_text(outfilename):
with open(outfilename, 'wb') as outfile:
for filename in glob.glob('*.txt'):
if filename == outfilename:
# don't want to copy the output into the output
continue
with open(filename, 'rb') as readfile:
outfile.write(readfile.read())
バイナリモードの実行時間-
Shutil - 20.161773920059204
Normal - 17.327500820159912
テキストモードの実行時間-
Shutil - 20.47757601737976
Normal - 13.718038082122803
どちらのモードでも、shutilは同じように動作しますが、テキストモードはバイナリより高速です。
OS:Mac OS 10.14 Mojave。 Macbook Air 2017。
すべてをメモリに読み込まずに、ファイルオブジェクトの行を直接反復処理できます。
with open(fname, 'r') as readfile:
for line in readfile:
outfile.write(line)