web-dev-qa-db-ja.com

pythonディレクトリ内のすべてのファイルを1つのファイルに連結するスクリプト

ディレクトリ内のすべてのファイルを1つのファイルに連結する次のスクリプトを作成しました。

これを最適化できますか

  1. 慣用的なpython

  2. 時間

これがスニペットです:

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")
14
user1629366

_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を使用する場合に特に重要です。ここでは両方にバイナリモードを使用しました。

31
Martijn Pieters

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でした。

2
Stephen Miller

それほど多くの変数を使用する必要はありません。

with open(outfilename, 'w') as outfile:
    for fname in filenames:
        with open(fname, 'r') as readfile:
            outfile.write(readfile.read() + "\n\n")
1
MGP

fileinput モジュールは、複数のファイルを反復する自然な方法を提供します

for line in fileinput.input(glob.glob("*.txt")):
    outfile.write(line)
1
iruvar

パフォーマンスの詳細を確認したいので、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。

1

すべてをメモリに読み込まずに、ファイルオブジェクトの行を直接反復処理できます。

with open(fname, 'r') as readfile:
    for line in readfile:
        outfile.write(line)
0
Brendan Long