在C#中为大文件创build校验和的最快方法是什么?

我必须在一些机器上同步大文件。 这些文件的大小可以达到6GB。 同步将每几周手动完成。 我不能考虑文件名,因为他们可以随时更改。

我的计划是在目标PC和源PC上创build校验和,然后将所有不在目标中的校验和的文件复制到目的地。 我的第一个尝试是这样的:

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); } } 

问题在于运行时间:
– SHA256与一个1,6 GB的文件 – > 20分钟
– 与MD5的1,6 GB的文件 – > 6.15分钟

有没有更好的方法来获得校验和(也许有更好的散列函数)?

这里的问题是SHA256Managed读取4096个字节(从FileStreaminheritance并覆盖Read(byte[], int, int)以查看从文件stream中读取多less),这对于磁盘IO来说太小了。

为了加快速度(在我的机器上使用SHA256散列2 Gb文件2分钟,MD5使用1分钟)在BufferedStream包装FileStream ,并设置合理大小的缓冲区大小(我尝试使用〜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 } 

不要校验整个文件,每100mb左右创build校验和,因此每个文件都有一个校验和集合。

然后在比较校验和时,可以在第一次不同的校验和之后停止比较,提早出来,并且不用处理整个文件。

它仍然需要全部时间来完成相同的文件。

正如Anton Gogolev指出的,FileStream默认一次读取4096个字节,但是您可以使用FileStream构造函数指定任何其他值:

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

请注意,微软的Brad Abrams在2004年写道:

在FileStream周围包装BufferedStream没有任何好处。 我们在4年前将BufferedStream的缓冲逻辑复制到FileStream中,以鼓励更好的默认性能

资源

调用md5sum.exe的Windows端口。 这大约是.NET实现的两倍(至less在我的机器上使用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 (); } 

好的 – 谢谢大家 – 让我把这个包起来:

  1. 使用“本机”EXE做哈希花了6分钟到10秒的时间,这是巨大的。
  2. 增加缓冲区速度更快 – 1.6GB文件需要5.2秒使用.net中的MD5,所以我会去这个解决scheme – 再次感谢

我做了缓冲区大小的testing,运行这个代码

 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(); } 

我testing了一个29½GB的文件,结果是

  • 10.000:369,24s
  • 100.000:362,55s
  • 1.000.000:361,53s
  • 10.000.000:434,15s
  • 100.000.000:435,15s
  • 1,000,000,000:434,31s
  • 而376,22的时候使用原始的,没有缓冲的代码。

我正在运行一个i5 2500K CPU,12 GB RAM和一个OCZ Vertex 4 256 GB SSD驱动器。

所以我想,怎么样一个标准的2TB硬盘。 结果是这样的

  • 10.000:368,52s
  • 100.000:364,15s
  • 1.000.000:363,06s
  • 10.000.000:678,96s
  • 100.000.000:617,89s
  • 1.000.000.000:626,86s
  • 没有缓冲368,24

所以我会build议不要缓冲区或最大1磨的缓冲区。

你做错了什么(可能太小的读取缓冲区)。 在一个年龄不太老的机器上(从2002年开始Athlon 2x1800MP),在磁盘上有DMA(6.6M / s,在连续读取的时候速度很慢):

用“随机”数据创build一个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 

1m5.299s

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

1m58.832s

这也是奇怪的,md5对我来说一直比sha1慢(reran几次)。