web-dev-qa-db-ja.com

ファイルが同一かどうかを確認する最も速い方法は何ですか?

1,000,0000のソースファイルがある場合、それらはすべて同じであると疑っており、それらのファイルを比較するための現在の断食方法は何ですか?それらがJava=ファイルとプラットフォームであり、比較が行われる場所は重要ではないと想定します。cksumは私を泣かせます。同一とは、すべて同一という意味です。

pdate:チェックサムの生成について知っています。差分が笑える…スピードが欲しい。

pdate:それらがソースファイルであるという事実にとらわれないでください。たとえば、出力が非常に規制されているプログラムを100万回実行したとしましょう。出力の1,000,000バージョンがすべて同じであることを証明したいとします。

pdate:バイトではなくブロック数を読み取りますか?すぐに捨てる?バイト数を見つけるよりも速いですか?

更新:これは、2つのファイルを比較する最速の方法とは異なりますか?

31
ojblass

cmpプログラムのアプローチのようなものを選びます。2つのファイル(ファイル1とファイル2など)を開き、それぞれからブロックを読み取り、バイトごとに比較します。一致する場合は、それぞれから次のブロックを読み取り、バイト単位で比較します。違いを検出せずに両方のファイルの終わりに到達した場合は、ファイル1の先頭に移動して、ファイル2を閉じ、ファイル3を開きます。代わりに、すべてのファイルをチェックするまで繰り返します。実際にはすべて同じである場合、すべてのファイルのすべてのバイトを読み取るのを回避する方法はないと思いますが、このアプローチは、存在する可能性のある違いを検出する最も速い方法(またはそれに近い方法)だと思います。

OP変更Mark Bessey からの重要なコメントを引き上げ

「ファイルがほとんど同一であると予想され、ファイルが比較的小さい場合のもう1つの明らかな最適化は、ファイルの1つを完全にメモリに保持することです。これにより、2つのファイルを同時に読み取ろうとするスラッシングを大幅に削減できます。」

23
David Z

回答者のほとんどは、ファイルを繰り返し比較する必要があるという事実を無視しています。したがって、チェックサムが1回計算されてメモリに格納されるため、ファイルを連続してn回読み取る代わりに、チェックサムが高速になります。

14
Doug Bennett

ファイルが同じであることを期待していると仮定すると(それはシナリオのように聞こえます)、チェックサム/ハッシュを処理することは時間の無駄です-それらは同じである可能性が高く、再実行する必要がありますファイルを読み取って最終的な証明を取得します(「証明...が同じである」ことを望んでいるため、同じ値にハッシュするだけでは十分ではないと想定しています)。

それが事実である場合、私は Davidによって提案されたソリューション があなたがする必要があるものにかなり近いと思います。複雑さを増すレベルで、比較を最適化するために実行できるいくつかのこと:

  • 比較を行う前に、ファイルサイズが同じかどうかを確認してください
  • 可能な限り最速のmemcmp()を使用します(バイトの代わりに単語を比較します-ほとんどのCランタイムはこれをすでに実行しているはずです)
  • 複数のスレッドを使用してメモリブロックの比較を実行します(システムで使用可能なプロセッサの数まで、これを超えるとスレッドが互いに競合します)
  • オーバーラップ/非同期I/Oを使用して、I/Oチャネルをできるだけビジー状態に保ちますが、プロファイルを慎重に行って、ファイル間のスラッシュをできるだけ少なくします(ファイルが複数の異なるディスクとI/Oポートに分割されている場合、すべてよりいい)
8
Michael Burr

更新:それらがソースファイルであるという事実にとらわれないでください。たとえば、非常に規制された出力でプログラムを100万回実行したとしましょう。出力のすべての1,000,000バージョンが同じであることを証明したいとします。

出力を制御している場合は、プログラムがファイルを作成する/出力でmd5をオンザフライで作成し、ファイルまたは出力ストリームに埋め込むか、途中でmd5を作成して横に保存するプログラムに出力をパイプしますデータはどういうわけか、バイトがすでにメモリにあるときに計算を行うことがポイントです。

他の人が言ったようにこれを引き出すことができない場合は、ファイルサイズを確認してから、同じサイズのファイルでバイト単位のストレート比較を行ってください。バイナリ除算やmd5計算は、ストレートよりも優れています。比較すると、すべてのバイトに触れて等価性を証明する必要があるため、バイトごとに必要な計算量を削減し、不一致が見つかるとすぐに遮断できるようにする必要があります。

これらを後で新しい出力と比較する予定がある場合は、md5の計算が役立ちますが、基本的には、できるだけ早くmd5を計算するという最初のポイントに戻ります。

5
mark

一般に一連のファイルを比較して同一のファイルを見つけるプログラムは多数あります。 FDUPESは良いものです Link 。入力の正確な性質によっては、100万のファイルが問題になることはありません。 FDUPESにはLinuxが必要だと思いますが、他のプラットフォーム用のプログラムも他にもあります。

自分で高速なプログラムを書こうとしましたが、特別な場合を除いて、FDUPESの方が高速でした。

とにかく、一般的なアイデアは、ファイルのサイズを確認することから始めることです。サイズが異なるファイルを同じにすることはできないため、同じサイズのファイルのグループを調べるだけで済みます。次に、最適なパフォーマンスが必要な場合は、さらに複雑になります。ファイルが異なる可能性がある場合は、ファイルの小さな部分を比較して、違いを早期に発見できるようにして、残りのファイルを読む必要がないようにします。ただし、ファイルが同一である可能性が高い場合は、各ファイルを読み取ってチェックサムを計算する方が高速です。これは、2つ以上のファイル間を行き来する代わりに、ディスクから順次読み取ることができるためです。 (これは通常のディスクを想定しているため、SSD:は異なる場合があります。)

私のベンチマークでは、より高速なプログラムを作成しようとしたときに、(やや驚いたことに)最初に各ファイルを読み取ってチェックサムを計算し、チェックサムが等しい場合は、ブロックを交互に読み取ってファイルを直接比較する方が速いことがわかりました以前のチェックサム計算なしでブロックを交互に読み取るよりも、各ファイルから! Linuxはチェックサムを計算するときに、両方のファイルをメインメモリにキャッシュし、各ファイルを順番に読み取り、2回目の読み取りは非常に高速であることがわかりました。交互読み取りで開始すると、ファイルは(物理的に)順次読み取られませんでした。

編集:

一部の人々は、ファイルを1度だけ読むよりも2度読む方が速いかもしれないという驚きと疑いを表明しました。たぶん、自分が何をしているのかはっきりと説明できなかったのかもしれません。物理ディスクドライブで行うのが遅い方法で後でアクセスするときにファイルをディスクキャッシュに入れるために、キャッシュのプリロードについて話しています。 ここ は、写真、Cコード、および測定値を使用して、より詳細に説明しようとしたWebページです。

ただし、これは(せいぜい)元の質問にわずかに関連します。

最初に、100万件すべてのファイルの長さを比較します。安価な方法がある場合は、最大のファイルから始めます。それらすべてが合格した場合、バイナリ除算パターンを使用して各ファイルを比較します。これは、似ているが同じではないファイルではより速く失敗します。この比較方法の詳細については、「 Knuth-Morris-Prattメソッド 」を参照してください。

2
Peter Wone

最適なアルゴリズムは、重複するファイルの数によって異なります。

いくつかは同じであると仮定しますが、ほとんどは異なり、ファイルは大きくなります。

単純なファイル長チェックを使用して、明らかに同じでないものを除外します。

ファイルからランダムなバイトを選択し、ハッシュを計算して比較します(ディスクシークを最小化します)。

完全なファイルSHA1でそれに続きます。

2
Sam Saffron

ハッシュがバイトごとの比較よりも速くなるとは思いません。バイトごとの比較は、バイトの読み取りと比較をパイプライン処理することによって少し最適化できます。また、ファイルの複数のセクションを並列スレッドで比較することもできます。それはこのようなものになるでしょう:

  • ファイルサイズが異なるかどうかを確認する
  • ファイルのブロックを非同期でメモリに読み込む
  • それらをワーカースレッドに渡して比較を行う

または、cmp(またはOSの同等のもの)を並行して実行します。これは簡単にスクリプト化することができ、それでも並列処理の利点を得ることができます。

1
BeWarned

ブルームフィルターの概念を使用します。ここで簡単な説明: http://crzyjcky.com/2013/01/03/the-magical-bloom-filter/

それはあなたに比較の一定の時間を与えます。ただし、この方法を単独で使用することはできません。 Apache CassandraおよびHBaseは、この手法を内部で使用しています。

基本的に、ファイルが非常に高速な方法で同一ではないことをuに伝えます。ファイルが同一であると表示された場合は、信頼できる方法を使用してもう一度チェックを行う必要があります。

1
janetsmith

cksumの使用は、md5sumなどの使用ほど信頼性が高くありません。しかし、私は最大の信頼性を選択します。つまり、cmpを使用したバイトごとの比較です。

すべてのチェック方法で両方のファイルのすべてのバイトを読み取る必要があるため、最も信頼できるものを選択することもできます。

最初のパスとして、ディレクトリリストをチェックして、サイズが異なるかどうかを確認できます。これは、さまざまなファイルのフィードバックをすばやく取得するための簡単な方法です。

1
paxdiablo

私の意見では、これはファイルシステムの操作です。したがって、最初にファイルシステムを慎重に選択してください。次に、重複排除します。次に、iノードを比較します。お気に入り:

% find / -inum "$(ls -di "./test.file" | grep -E '^[0-9]*')"
<list of identical files provided in a few seconds to a minute>
0
mikeserv

比較を超えて、2つのフォルダを同期、超高速!私たちは毎日、毎日それを使用しています。

0
bo.

ファイルを1つずつ比較する場合は、ExamDiffを使用します。

0
md27

私はこのようなものを実行します

find -name \*.Java -print0 | xargs -0 md5sum | sort

次に、MD5サムが異なるファイルを確認します。これにより、チェックサムごとにファイルがグループ化されます。

Md5sum、sha1sum、または必要に応じてrmd160を置き換えることができます。

0
Blair Zajac

私はあなたが望むものに似た何かをするc#アプリを書いたところです。私のコードが行うことはこれです。

各ファイルのサイズをすべて読み取り、リストまたは配列にします。

これらのサイズのいずれかが同じかどうかを確認するには、forループを使用します。それらが同じサイズの場合は、1つのファイルのバイトを他のファイルのバイトと比較します。 2バイトが同じ場合は、次のバイトに移動します。違いが見つかった場合は、ファイルが異なることを返します。

両方のファイルの終わりに達し、最後の2バイトが同じである場合、ファイルは同一である必要があります。

私は、バイトごとに処理するのではなく、ファイルのMD5ハッシュを比較する実験を行ったところ、この方法では同じファイルが見落とされることが多いことがわかりましたが、非常に高速です。

0
Ryan

なぜ車輪を再発明するのですか?サードパーティのアプリはどうですか? APIがないことは確かですが、このような状況に頻繁に陥るとは思いません。私はこのアプリが好き doublekiller 始める前にバックアップを作成するだけです。 :)それは高速で無料です!

0
NitroxDM