web-dev-qa-db-ja.com

ファイルを連結する最速の方法

合計20GBを超える10k以上のファイルがあり、1つのファイルに連結する必要があります。

より速い方法はありますか

cat input_file* >> out

推奨される方法はbashコマンドです。Pythonも、かなり遅くない場合でも受け入れられます。

26
fsperrle

いいえ、猫は確かにこれを行うための最良の方法です。なぜpythonを使用して、この目的のためにすでにCで書かれたプログラムがあるのですか?しかし、コマンドラインの長さがARG_MAXを超えており、必要な場合にxargs複数のcat。GNUツールを使用すると、これはすでに持っているものと同等です:

find . -maxdepth 1 -type f -name 'input_file*' -print0 |
  sort -z |
  xargs -0 cat -- >>out
30
Graeme

最初に出力ファイルにスペースを割り当てると、システムがすべての書き込みの割り当てを更新する必要がないため、全体的な速度が向上する場合があります。

たとえば、Linuxの場合:

size=$({ find . -maxdepth 1 -type f -name 'input_file*' -printf '%s+'; echo 0;} | bc)
fallocate -l "$size" out &&
  find . -maxdepth 1 -type f -name 'input_file*' -print0 |
  sort -z | xargs -r0 cat 1<> out

もう1つの利点は、十分な空き領域がない場合、コピーが試行されないことです。

btrfsの場合、copy --reflink=always最初のファイル(これはデータのコピーがないことを意味するため、ほとんど瞬時に実行されます)に残りを追加します。 10000個のファイルがある場合、最初のファイルが非常に大きくない限り、おそらく大きな違いはありません。

すべてのファイルを参照コピーするためにそれを一般化するAPIがあります(BTRFS_IOC_CLONE_RANGEioctl)ですが、そのAPIを公開しているユーティリティが見つからなかったため、C(またはpythonまたは他の言語で任意のioctls)。

ソースファイルがスパースであるか、NUL文字のシーケンスが大きい場合、(on GNU systems)を使用してスパース出力ファイル(時間とディスク領域を節約)を作成できます。

find . -maxdepth 1 -type f -name 'input_file*' -print0 |
  sort -z | xargs -r0 cat | cp --sparse=always /dev/stdin out
22