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


25

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

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

cat input_file* >> out

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


答えを更新しましたfind。シェルグロブと同じようにファイルをソートしません。
グレアム14年

5
時間が99%のシステムI / Oになるため、すべての(健全な)ソリューションの速度は同等になります。
goldilocks 14年


3
読み取り中のディスクとは異なるディスクに連結ファイルを書き込むことを検討してください。
ルイス14年

1
out別のディスクにある場合は高速になります。

回答:


30

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

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

1
この場合、ファイルが順番に読み取られることを保証できますか?
キウィ14年

1
はい、の出力はfindを介してパイプされるためsortです。これがないと、ファイルは任意の順序でリストされます(ファイルシステムで定義され、ファイル作成順序になる可能性があります)。
SCAI

@scai I missread申し訳ありませんが、ソートして、それはかなり明白だ
Kiwy

1
@Kiwy、私が見ることができる唯一のケースは、ロケールが環境で適切に設定されていない場合、ソートはbashグロブとは異なる動作をする可能性があることです。そうしないと、期待どおりに動作する、xargsまたはcat動作しないケースは見当たりません。
グレアム

3
@MarcvanLeeuwenは、execve(2)のE2BIGエラーを回避するために必要に応じてxargs呼び出しますcat
ステファンシャゼル14年

21

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

たとえば、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個のファイルがある場合、最初のファイルが非常に大きい場合を除き、おそらくそれほど違いはありません。

そこにすべてのファイルを(REF-コピーすることを一般化するAPIだBTRFS_IOC_CLONE_RANGE ioctl)が、あなたがCでそれをしなければならないと思いますので、私は、そのAPIをさらす任意の有用性を見出すことができませんでした(またはpythonあるいは他の言語は、彼らが任意呼び出すことができます提供ioctl秒) 。

ソースファイルがスパースであるか、NUL文字の大きなシーケンスを持っている場合、(GNUシステム上で)スパース出力ファイルを作成できます(時間とディスク容量を節約します)。

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

1
@XTian、いや、それはする必要がありますどちら>>>、しかし1<>私は、書き込みに言ったよう、ファイル。
ステファンシャゼル14年

5
@grebneke <>は、標準のBourne / POSIX読み取り/書き込みリダイレクト演算子です。詳細については、シェルマニュアルまたはPOSIX仕様を参照してください。デフォルトではfdある0ため<>、オペレータ(<>の略である0<>ように、<短いためである0<>短いために1>必要なので、)1明示的にリダイレクトstdoutに。ここでは、read + write(O_RDWR)が必要なほど多くはありませんが、O_TRUNC(のように>)割り当てたばかりの割り当てを解除する必要はありません。
ステファンシャゼル14年

1
@ grebneke、unix.stackexchange.com / search?q = user%3A22565 +%22%3C%3E%22がいくつかを提供します。ksh93にはシーク演算子BTWがあり、ddリーディングを使用して、またはリーディングを介してシークできます。
ステファンシャゼル14年

1
@StephaneChazelas-どうもありがとう、あなたの助けと知識は大歓迎です!
グレブネケ14年

1
2回目のラウンドではより高速になりfallocateますが、extraのオーバーヘッドを打ち消すケースが多いとは思いませんfindbtrfs確かにいくつかの興味深い可能性を開きます。
グレアム14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.