137

一部のマシン間で大きなファイルを同期する必要があります。ファイルのサイズは最大6GBです。同期は数週間ごとに手動で行われます。ファイル名はいつでも変更される可能性があるため、考慮に入れることはできません。

私の計画では、宛先PCとソースPCでチェックサムを作成してから、まだ宛先にないチェックサムを含むすべてのファイルを宛先にコピーします。私の最初の試みは次のようなものでした:

using System.IO;
using System.Security.Cryptography;

private static string GetChecksum(string file)
{
    using (FileStream stream = File.OpenRead(file))
    {
        SHA256Managed sha = new SHA256Managed();
        byte[] checksum = sha.ComputeHash(stream);
        return BitConverter.ToString(checksum).Replace("-", String.Empty);
    }
}

問題はランタイムでした:
-1,6GBファイルのSHA256の場合->20分-1.6GBファイル
のあるMD5の場合->6.15分

チェックサムを取得するためのより良い(より速い)方法はありますか(おそらくより良いハッシュ関数を使用して)?

4

9 に答える 9

124

ここでの問題はSHA256Managed、一度に 4096 バイトを読み取ることです (ファイルストリームからの読み取り量を継承FileStreamおよびオーバーライドRead(byte[], int, int)して確認します)。これは、ディスク IO のバッファーとしては小さすぎます。

スピードアップするには (私のマシンで SHA256 を使用して 2 Gb ファイルをハッシュするのに 2 分、MD5 で 1 分)、適切なサイズのバッファー サイズをラップFileStreamBufferedStreamて設定します (約 1 Mb のバッファーで試しました)。

// Not sure if BufferedStream should be wrapped in using block
using(var stream = new BufferedStream(File.OpenRead(filePath), 1200000))
{
    // The rest remains the same
}
于 2009-07-24T13:41:16.980 に答える
72

ファイル全体をチェックサムしないでください。100 MB ごとにチェックサムを作成して、各ファイルにチェックサムのコレクションが含まれるようにします。

次に、チェックサムを比較するときに、最初の異なるチェックサムの後に比較を停止し、早期に終了して、ファイル全体の処理を節約できます。

同一のファイルの場合は、まだ完全な時間がかかります。

于 2009-07-24T13:26:40.837 に答える
54

Anton Gogolev が指摘したように、FileStream はデフォルトで一度に 4096 バイトを読み取りますが、FileStream コンストラクターを使用して他の値を指定できます。

new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 16 * 1024 * 1024)

Microsoft の Brad Abrams が 2004 年に書いたことに注意してください。

FileStream を BufferedStream でラップしても何のメリットもありません。デフォルトのパフォーマンスを向上させるために、約 4 年前に BufferedStream のバッファリング ロジックを FileStream にコピーしました。

ソース

于 2015-01-17T13:42:57.883 に答える
23

md5sum.exeの Windows ポートを呼び出します。.NET 実装の約 2 倍の速度です (少なくとも、1.2 GB ファイルを使用する私のマシンでは)。

public static string Md5SumByProcess(string file) {
    var p = new Process ();
    p.StartInfo.FileName = "md5sum.exe";
    p.StartInfo.Arguments = file;            
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.RedirectStandardOutput = true;
    p.Start();
    p.WaitForExit();           
    string output = p.StandardOutput.ReadToEnd();
    return output.Split(' ')[0].Substring(1).ToUpper ();
}
于 2009-07-24T13:37:00.387 に答える
17

わかりました - 皆さんに感謝します - これをまとめさせてください:

  1. 「ネイティブ」exeを使用してハッシュを行うと、6 分から 10 秒かかりました。これは膨大な時間です。
  2. バッファの増加はさらに高速でした.NETでMD5を使用すると1.6GBのファイルに5.2秒かかったので、このソリューションを使用します-ありがとうございました
于 2009-07-24T14:26:49.397 に答える
10

このコードを実行して、バッファサイズでテストを行いました

using (var stream = new BufferedStream(File.OpenRead(file), bufferSize))
{
    SHA256Managed sha = new SHA256Managed();
    byte[] checksum = sha.ComputeHash(stream);
    return BitConverter.ToString(checksum).Replace("-", String.Empty).ToLower();
}

サイズが 29½ GB のファイルでテストしたところ、結果は次のようになりました。

  • 10.000: 369,24 秒
  • 100.000: 362,55 秒
  • 1.000.000: 361,53 秒
  • 10.000.000: 434,15 秒
  • 100.000.000: 435,15 秒
  • 1.000.000.000: 434,31 秒
  • また、元のバッファリングされていないコードを使用すると、376,22 秒になります。

i5 2500K CPU、12 GB RAM、および OCZ Vertex 4 256 GB SSD ドライブを実行しています。

そこで私は、標準の 2TB ハードドライブはどうだろうかと考えました。で、結果はこんな感じでした

  • 10.000: 368,52 秒
  • 100.000: 364,15 秒
  • 1.000.000: 363,06 秒
  • 10.000.000: 678,96 秒
  • 100.000.000: 617,89 秒
  • 1.000.000.000: 626,86 秒
  • そして、バッファリングされていない場合は 368,24

したがって、バッファーなし、または最大 1 ミルのバッファーをお勧めします。

于 2012-10-07T19:38:28.423 に答える
4

私はパーティーに遅れていることを知っていますが、実際にソリューションを実装する前にテストを実行しました。

組み込みの MD5 クラスとmd5sum.exeに対してテストを実行しました。私の場合、組み込みクラスは 13 秒かかりましたが、md5sum.exe は実行ごとに約 16 ~ 18 秒かかりました。

    DateTime current = DateTime.Now;
    string file = @"C:\text.iso";//It's 2.5 Gb file
    string output;
    using (var md5 = MD5.Create())
    {
        using (var stream = File.OpenRead(file))
        {
            byte[] checksum = md5.ComputeHash(stream);
            output = BitConverter.ToString(checksum).Replace("-", String.Empty).ToLower();
            Console.WriteLine("Total seconds : " + (DateTime.Now - current).TotalSeconds.ToString() + " " + output);
        }
    }
于 2019-03-16T13:46:33.037 に答える
2

何か間違ったことをしています (おそらく読み取りバッファが小さすぎます)。ディスク上に DMA があり、おそらく調子が悪い (6.6M/s は、シーケンシャル読み取りを行うと非常に遅い) 不適切な年齢のマシン (2002 年からの Athlon 2x1800MP) では:

「ランダム」データで 1G ファイルを作成します。

# dd if=/dev/sdb of=temp.dat bs=1M count=1024    
1073741824 bytes (1.1 GB) copied, 161.698 s, 6.6 MB/s

# time sha1sum -b temp.dat
abb88a0081f5db999d0701de2117d2cb21d192a2 *temp.dat

1分5.299秒

# time md5sum -b temp.dat
9995e1c1a704f9c1eb6ca11e7ecb7276 *temp.dat

1分58.832秒

これも奇妙です.md5は一貫してsha1よりも遅いです(数回再実行しました)。

于 2009-07-24T13:56:37.727 に答える