2010-01-23 59 views
31

我需要计算相当大的文件(千兆字节)的校验和。这可以通过以下方法来完成:可能用缓冲读取计算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(或其他)哈希,即:计算一个缓冲区的哈希值,然后将得到的哈希值送入下一次迭代。

事情是这样的:(伪-ISH)

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

散列现在sililar什么会运行整个文件的calcHash功能来实现。

现在,我无法在.Net 3.5框架中找到任何重写,我在做梦吗?它从来没有存在过,还是我只是在搜索?同时执行写入和校验和计算的原因是由于大文件造成的。

回答

45

您使用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; 

注:它的工作原理(至少与MD5提供商)所有块发送到TransformBlock,然后发送一个空块TransformFinalBlock敲定过程。

+1

omg,只是发布了相同的建议,使用相同的格式=) – 2010-01-23 20:03:19

+0

好吧,但+1也提供了一个参考! – 2010-01-23 20:05:19

+1

Ay caramba!它是!这是我正在寻找的功能。很高兴知道我没有完全掌握。感谢Guffa和Rubens及时提供正确答案。 +1给你们两个,我会接受这个答案,因为包含的代码示例。 – 2010-01-23 20:31:34

3

的哈希算法,预计来处理这种情况,通常与3个功能实现:

hash_init() - 被叫分配资源,并开始哈希值。
hash_update() - 在新数据到达时调用。
hash_final() - 完成计算和免费资源。

看看http://www.openssl.org/docs/crypto/md5.htmlhttp://www.openssl.org/docs/crypto/sha.html为好,标准例子在C;我相信你的平台有类似的库。

+0

很好的答案,但“在.net中它在哪里?”部分问题仍然存在。 – 2010-01-23 19:58:23

+0

@帕斯卡尔:看到下面的两个很好的答案,这两个答案都在你的评论之前发布。 – 2010-01-23 20:06:12

4

似乎可以使用TransformBlock/TransformFinalBlock,如图此示例中:Displaying progress updates when hashing large files

+0

那个链接已经死了,试试这个:http://www.infinitec.de/post/2007/06/09/Displaying-progress-updates-when-hashing-large-files.aspx – Cumbayah 2011-10-19 08:26:52

48

我喜欢以上但为完整起见答案,并成为一个更通用的解决方案,请参阅CryptoStream类。如果您已经处理了流,则很容易将流包装在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)); 

您可能必须获得哈希(所以HashAlgorithm知道它做)前关闭流。

0

我只是不得不做类似的事情,但想要异步读取文件。它使用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); 
    } 
} 
+0

什么是'ArrayPool'? – Shimmy 2018-02-25 07:31:38

+0

行了:['ArrayPool'](https://github.com/dotnet/corefx/blob/master/src/System.Buffers/src/System/Buffers/ArrayPool.cs),需要安装软件包['' System.Buffers'](https://preview.nuget.org/packages/System.Buffers)。 – Shimmy 2018-02-25 07:34:00