2010-01-23 62 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