可能用缓冲读取来计算MD5(或其他)散列?

我需要计算相当大的文件(千兆字节)的校验和。 这可以使用以下方法来完成:

private byte[] calcHash(string file) { System.Security.Cryptography.HashAlgorithm ha = System.Security.Cryptography.MD5.Create(); FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read); byte[] hash = ha.ComputeHash(fs); fs.Close(); return hash; } 

但是,这些文件通常是以缓冲的方式预先写入的(比如说一次写入32mb的文件)。 我深信,我看到了一个哈希函数的重写,它允许我在写入的同时计算MD5(或其他)哈希值,即:计算一个缓冲区的哈希值,然后将得到的哈希值送入下一次迭代。

像这样的东西:(pseudocode-ish)

 byte [] hash = new byte [] { 0,0,0,0,0,0,0,0 }; while(!eof) { buffer = readFromSourceFile(); writefile(buffer); hash = calchash(buffer, hash); } 

哈希现在与通过在整个文件上运行calcHash函数完成的操作相似。

现在,我在.Net 3.5框架中找不到像这样的重写,我在做梦吗? 它从来没有存在过,还是我只是在search? 同时进行写入和校验和计算的原因是由于大文件造成的。

您使用TransformBlockTransformFinalBlock方法来处理块中的数据。

 // Init MD5 md5 = MD5.Create(); int offset = 0; // For each block: offset += md5.TransformBlock(block, 0, block.Length, block, 0); // For last block: md5.TransformFinalBlock(block, 0, block.Length); // Get the has code byte[] hash = md5.Hash; 

注意:它起作用(至less在MD5提供程序中)将所有块发送到TransformBlock ,然后将空块发送到TransformFinalBlock以完成该过程。

我喜欢上面的答案,但为了完整起见,作为更一般的解决scheme,请参阅CryptoStream类。 如果你已经处理了stream,很容易把你的stream封装到CryptoStream ,传递一个HashAlgorithm作为ICryptoTransform参数。

 var file = new FileStream("foo.txt", FileMode.Open, FileAccess.Write); var md5 = MD5.Create(); var cs = new CryptoStream(file, md5, CryptoStreamMode.Write); while (notDoneYet) { buffer = Get32MB(); cs.Write(buffer, 0, buffer.Length); } System.Console.WriteLine(BitConverter.ToString(md5.Hash)); 

在得到散列之前,你可能不得不closuresstream(所以HashAlgorithm知道它已经完成了)。

似乎可以使用TransformBlock / TransformFinalBlock ,如下例所示: 散列大文件时显示进度更新

预期散列algorithm可以处理这种情况,通常用3个函数来实现:

hash_init() – 调用来分配资源并开始散列。
hash_update() – 在新数据到达时调用。
hash_final() – 完成计算和空闲资源。

请看http://www.openssl.org/docs/crypto/md5.html或http://www.openssl.org/docs/crypto/sha.html,获取C语言中的标准示例;; 我相信你的平台有类似的库。

我只是不得不做类似的事情,但想要asynchronous读取文件。 它使用TransformBlock和TransformFinalBlock,并给出了与Azure一致的答案,所以我认为这是正确的!

 private static async Task<string> CalculateMD5Async(string fullFileName) { var block = ArrayPool<byte>.Shared.Rent(8192); try { using (var md5 = MD5.Create()) { using (var stream = new FileStream(fullFileName, FileMode.Open, FileAccess.Read, FileShare.Read, 8192, true)) { int length; while ((length = await stream.ReadAsync(block, 0, block.Length).ConfigureAwait(false)) > 0) { md5.TransformBlock(block, 0, length, null, 0); } md5.TransformFinalBlock(block, 0, 0); } var hash = md5.Hash; return Convert.ToBase64String(hash); } } finally { ArrayPool<byte>.Shared.Return(block); } }