2012-04-26 23 views
5

我正試圖設計一個簡單的應用程序來計算文件的CRC32/MD5/SHA1/SHA256/SHA384/SHA512,並且我遇到了一點障礙。這是在C#中完成的。如何在同一時間以多種方式散列單個文件?

我希望能夠儘可能有效地做到這一點,所以我最初的想法是在處理之前先將文件讀入內存流中,但我很快發現非常大的文件會導致內存不足很快。所以看起來我必須改用文件流。正如我所看到的那樣,問題是一次只能運行一個散列函數,而使用文件流執行散列函數需要一段時間才能完成每個散列函數。

我該如何去讀取一小段文件到內存中,使用所有6種算法處理它,然後進入另一個塊......或者散列法不是以這種方式工作?

這是我最初嘗試將文件讀入內存。它沒有當我試圖運行在MemoryStream的哈希算法之前讀取CD映像裝入內存:

private void ReadToEndOfFile(string filename) 
    { 
     if (File.Exists(filename)) 
     { 
      FileInfo fi = new FileInfo(filename); 
      FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read); 
      byte[] buffer = new byte[16 * 1024]; 

      //double step = Math.Floor((double)fi.Length/(double)100); 

      this.toolStripStatusLabel1.Text = "Reading File..."; 
      this.toolStripProgressBar1.Maximum = (int)(fs.Length/buffer.Length); 
      this.toolStripProgressBar1.Value = 0; 

      using (MemoryStream ms = new MemoryStream()) 
      { 
       int read; 
       while ((read = fs.Read(buffer, 0, buffer.Length)) > 0) 
       { 
        ms.Write(buffer, 0, read); 
        this.toolStripProgressBar1.Value += 1; 
       } 

       _ms = ms; 
      } 
     } 
    } 

回答

3

你是那裏的大部分,你只需要不需要一次性將所有東​​西讀入內存。

.Net中的所有哈希值都從HashAlgorithm類派生。這有兩種方法:TransformBlockTransformFinalBlock。所以,你應該能夠爲你的文件讀取一個塊,將它填入你想使用的任何一個哈希的TransformBlock方法中,然後移動到下一個塊中。只要記得從文件中調用TransformFinalBlock作爲你的最後一個塊,因爲這是你得到包含散列的字節數組。

現在,我只想做每個哈希一次一個,直到它的工作,然後擔心運行散列同時(使用類似任務並行庫)

+0

我試過讓這個工作使用MD5,程序運行,雖然它似乎是生成不正確的散列。 這是我的代碼鏈接:[鏈接](http://pastebin.com/i3iPwYZv) – agent154 2012-04-26 23:52:16

+1

調用'TransformFinalBlock'時應該使用'read'而不是'buffer.Length' – 2012-04-27 05:41:06

+0

非常感謝!我昨晚爲此苦苦了一陣子。結束了一些愚蠢的行爲,希望能夠實現它,但我忍不住覺得這是沒有必要的。 我發現這是因爲最後一個數組被完全讀取,即使最後一個數據塊對它來說太小。我最終創建了一個新的字節數組,最後一塊等於最後一個塊的大小。 – agent154 2012-04-27 11:50:02

4

哈希算法被設計的方式,你可以增量計算哈希值。您可以找到該here的C#/ .NET示例。您可以輕鬆修改提供的代碼以在每個步驟中更新多個哈希算法實例。

0

這可能是一個很好的機會獲得你的腳沾滿了TPL數據流對象。在一個線程中讀取文件並將數據發佈到BroadcastBlock<T>BroadcastBlock<T>將鏈接到6個不同的ActionBlock<T>實例。每個ActionBlock<T>將對應您的6個散列策略之一。

var broadcast = new BroadcastBlock<byte[]>(x => x); 

var strategy1 = new ActionBlock<byte[]>(input => DoHash(input, SHA1.Create())); 
var strategy2 = new ActionBlock<byte[]>(input => DoHash(input, MD5.Create())); 
// Create the other 4 strategies. 

broadcast.LinkTo(strategy1); 
broadcast.LinkTo(strategy2); 
// Link the other 4. 

using (var fs = File.Open(@"yourfile.txt", FileMode.Open, FileAccess.Read)) 
using (var br = new BinaryReader(fs)) 
{ 
    while (br.PeekChar() != -1) 
    { 
    broadcast.Post(br.ReadBytes(1024 * 16)); 
    } 
} 

BroadcastBlock<T>將每個數據塊轉發到所有鏈接ActionBlock<T>實例。

由於您的問題集中在如何讓這一切同時發生,我將離開實施DoHash由您決定。

private void DoHash(byte[] input, HashAlgorithm algorithm) 
{ 
    // You will need to implement this. 
} 
+0

這看起來像是一個非常有趣的多線程方法。恥辱它在.net 4.5。無論出於何種原因,我有足夠的時間讓自己說服自己使用.net 4.0,因爲它對我來說還不夠主流。 – agent154 2012-04-27 16:59:10

+0

看來這種方法不起作用。將爲每個輸入的字節數組調用DoHash。他們應該如何組合? – Petro 2015-03-18 15:35:15

相關問題