1

私には(どうやら)大きな仕事が迫っています。
複数のフォルダーの異なるアーカイブ ボリュームを調べる必要があります (数テラバイトのデータについて話している)。各フォルダー内には .pst ファイルがあります。これらのフォルダー (およびファイル) の一部は、まったく同じ (名前またはファイル内のデータ) である場合があります。一度に 2 つ以上のファイルを比較して (可能であれば)、重複が見つかるかどうかを確認したいと考えています。重複が見つかったら、それらを削除して元のメールを保持し、最終的に一意のメールをすべて抽出する必要があります。

重複を見つけることができるプログラムがあることは知っていますが、これらのファイルでどの引数を渡す必要があるかはわかりません。また、そのような大量のデータを処理できるかどうかもわかりません。C# か VB でプログラミングしたいと思っています。私はどこから始めるべきか途方に暮れています。助言がありますか??

元...

m:\mail\name1\name.pst

m:\mail\name2\name.pst (same exact data as the one above)

m:\mail\name3\anothername.pst (duplicate file to the other 2)
4

2 に答える 2

1

最初にすべての PST ファイルを再帰的に検索し、次にファイルの長さを照合し、次にバイトの固定プレフィックスでフィルター処理し、最後に完全なハッシュまたはバイト比較を実行して実際の一致を取得することにより、重複を見つけるプロセスを実行します。

リストを再帰的に構築し、潜在的な一致を見つけることは、次のように簡単です。

Func<DirectoryInfo, IEnumerable<FileInfo>> recurse = null;
recurse = di => di.GetFiles("*.pst")
    .Concat(di.GetDirectories()
        .SelectMany(cdi => recurse(cdi)));

var potentialMatches =
    recurse(new DirectoryInfo(@"m:\mail"))
        .ToLookup(fi => fi.Length)
        .Where(x => x.Skip(1).Any());

このpotentialMatchesクエリは、ファイル サイズごとに一連の潜在的な一致を提供します。

次に、次の関数 (実装はお任せします) を使用して、このリストをさらにフィルター処理します。

Func<FileInfo, FileInfo, int, bool> prefixBytesMatch = /* your implementation */
Func<FileInfo, FileInfo, bool> hashMatch = /* your implementation */

ファイルの長さで一致を制限し、次にバイトのプレフィックスで制限することにより、非常に大きなファイルに必要なハッシュの計算を大幅に削減できます。

これが役立つことを願っています。

于 2012-10-19T01:40:15.707 に答える
1

重複ファイル全体を削除するだけの場合、タスクの実装は非常に簡単です。

すべてのフォルダーを調べて、各ファイルの内容をハッシュする必要があります。生成されたハッシュには、いくつかのビット (たとえば、32 ~ 256 ビット) があります。2 つのファイル ハッシュが等しい場合、それぞれのファイルが同一である可能性が非常に高くなります (ハッシュ関数の衝突耐性、読み取りビット数によって異なります)。

もちろん、実装はあなた次第です (私は C# プログラマーでも VB プログラマーでもありません) が、次の疑似コードのようなものをお勧めします (次に、各ステップを説明し、C# でそれを行う方法を示すリンクを提供します)。 :

    do{
       file_byte_array = get_file_contents_into_byte_array(file)          1
       hash = get_hash from_byte_array(file_byte_array);                  2
       if(hashtable_has_elem(hashtable,hash))                             3
         remove_file(file);                                               4
       else                                                               5
         hashtable_insert_elem(hashtable,hash,file);                      6
     }while_there_are_files_to evaluate                                   7

このロジックは、すべての.pstファイルに対して実行する必要があります。1 行目 (ファイルを開いていると仮定します)で、ファイルのすべての内容をバイト配列に書き込みます。

ファイルのバイト配列を取得したら、ハッシュ関数を使用してそれをハッシュする必要があります (2 行目)。選択できるハッシュ関数の実装はたくさんあります。一部の実装では、ファイルをブロックに分割し、各ブロックの内容をハッシュする必要があります (例: herehere、およびhere )。ファイルが非常に巨大で、メモリに収まらない場合は、ファイルを分割することが唯一の選択肢かもしれません。一方、ストリーム全体を受け入れる多くの関数があります(たとえば、ここここにあなたの問題に非常によく似た例がありますここここですが、超高速のMurmurHash3をお勧めします)。効率が必要な場合は、暗号化ハッシュ関数を使用しないでください。暗号化ハッシュ関数ははるかに重く、タスクを実行するために暗号化プロパティは必要ありません。

最後に、ハッシュを計算した後、同一のハッシュを見つけて (ファイルを読み取り)、それらを削除するために、ハッシュを保存して比較する方法を取得する必要があります (3 ~ 6 行目)。ここでは、ハッシュ テーブルまたはディクショナリを使用することを目的としています。ここで、識別子 (ルックアップを実行するために使用するオブジェクト) はファイル ハッシュであり、オブジェクト File はエントリ値です。

ノート:

覚えておいてください!!!: ハッシュ値のビット数が多いほど、衝突の可能性は低くなります。ハッシュ関数の衝突確率について詳しく知りたい場合は、この優れた記事をお読みください。目的はファイルを削除することなので、このトピックに注意を払う必要があります。衝突が発生すると、同一でないファイルが 1 つ削除され、永久に失われます。衝突を特定する方法は多数あり、それらを組み合わせてアルゴリズムに追加できます (たとえば、ファイルのサイズを比較する、ランダムな位置でファイルの内容値を比較する、複数のハッシュ関数を使用する)。私のアドバイスは、これらすべての戦術を使用することです。2 つのハッシュ関数を使用する場合、2 つのファイルが同一と見なされるには、各ハッシュ関数のハッシュ値が等しい必要があります。

    file1, file2;
    file1_hash1  = hash_function1(file1);
    file2_hash1  = hash_function1(file2);
    file1_hash2  = hash_function2(file1);
    file2_hash2  = hash_function2(file2);

    if(file1_hash1 == file2_hash1 &&
       file2_hash2 == file2_hash2)
      // file1 is_duplicate_of file2;
    else
      // file1 is_NOT_duplicate_of file2;
于 2012-10-19T00:21:01.883 に答える