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

cro*_*ono 125 .net c# checksum large-files

我必须在一些机器上同步大文件.这些文件最大可达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);
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是运行时:
- 使用带有1,6 GB文件的SHA256 - > 20分钟
- 使用带有1.6 GB文件的MD5 - > 6.15分钟

是否有更好 - 更快 - 获得校验和的方法(可能具有更好的散列函数)?

Ant*_*lev 110

这里的问题是一次SHA256Managed读取4096个字节(继承FileStream和覆盖Read(byte[], int, int)以查看它从文件流中读取了多少),这对于磁盘IO来说太小了.

为了加快速度(2分钟散列的2 Gb我机SHA256,1分钟MD5上的文件)包裹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
}
Run Code Online (Sandbox Code Playgroud)

  • 派对有点晚了,但是对于FileStreams,不再需要将流包装在BufferedStream中,因为现在已经在FileStream本身中完成了.[来源](https://blogs.msdn.microsoft.com/brada/2004/04/15/filestream-and-bufferedstream/) (10认同)
  • 我不懂.我只是尝试了这个建议,但差别很小甚至没有.1024mb文件没有缓冲12-14秒,缓冲也是12-14秒 - 我知道读取数百个4k块将产生更多的IO但我问自己框架或框架下面的本机API是否已经不能处理这个.. (4认同)
  • 好的 - 这造成差异 - 使用MD5散列1.6GB文件在我的盒子上耗时5.2秒(QuadCode @ 2.6 GHz,8GB Ram) - 甚至更快,因为本机实现... (3认同)

Bin*_*ier 61

不要校验整个文件,每100mb左右创建校验和,因此每个文件都有一组校验和.

然后,在比较校验和时,您可以在第一个不同的校验和之后停止比较,提前退出,并避免处理整个文件.

它仍然需要相同文件的全部时间.

  • 我喜欢这个想法,但它在我的场景中不起作用,因为随着时间的推移我会得到很多未更改的文件. (2认同)
  • 你如何对文件的每 100mb 进行校验和? (2认同)
  • +1当您进行一对一比较时,这是一个绝妙的主意。不幸的是,我使用MD5哈希作为索引来查找许多重复项中的唯一文件(多对多检查)。 (2认同)
  • @b.kiener 没有字节被排除。你误会他了。 (2认同)

Tal*_*oni 44

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

new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 16 * 1024 * 1024)
Run Code Online (Sandbox Code Playgroud)

请注意,2004年Microsoft的Brad Abrams写道:

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

资源


Chr*_*rkl 22

调用md5sum.exe的Windows端口.它的速度大约是.NET实现速度的两倍(至少在使用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 ();
}
Run Code Online (Sandbox Code Playgroud)

  • 哇 - 使用pc-tools.net/win32/md5sums中的md5sums.exe会让它变得非常快.1681457152字节,8672 ms = 184.91 MB /秒 - > 1,6GB~9秒这对我来说足够快. (2认同)

cro*_*ono 16

好的 - 多亏你们所有人 - 让我把它包起来:

  1. 使用"本机"exe来进行散列需要6分钟到10秒的时间,这是巨大的.
  2. 增加缓冲区的速度更快 - 使用.Net中的MD5,1.6GB文件需要5.2秒,所以我将继续使用此解决方案 - 再次感谢


And*_*ers 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();
}
Run Code Online (Sandbox Code Playgroud)

我测试了一个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,22s.

我正在运行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

所以我建议不要缓冲或最大1磨的缓冲.