2012-07-12 169 views
1

我正在爲所選文件計算MD5,MD4,SHA1,SHA256,SHA512,RIPEMD160等。 我已經創建了以下算法,但它有問題。C#中的哈希計算

 string finalHash; 
     byte[] buffer; 
     byte[] oldBuffer; 
     int bytesRead; 
     int oldBytesRead; 
     long streamSize; 
     long totalBytesRead = 0; 
     try 
     { 
      if (!String.IsNullOrEmpty(selectedFile)) 
      { 
       _dataStream = File.OpenRead(selectedFile); 
       selectedFile = string.Empty; 
      } 
      foreach (var hashObject in from Control ctrl in Controls where ctrl is CheckBox && ((CheckBox)ctrl).Checked select HashObject) 
      { 
       //totalBytesRead = 0; 
       streamSize = _dataStream.Length; 
       buffer = new byte[4096]; 
       bytesRead = _dataStream.Read(buffer, 0, buffer.Length); 
       totalBytesRead += bytesRead; 
       do 
       { 
        oldBytesRead = bytesRead; 
        oldBuffer = buffer; 
        buffer = new byte[4096]; 
        bytesRead = _dataStream.Read(buffer, 0, buffer.Length); 
        totalBytesRead += bytesRead; 
        if (bytesRead == 0) 
        { 
         hashObject.TransformFinalBlock(oldBuffer, 0, oldBytesRead); 
        } 
        else 
        { 
         hashObject.TransformBlock(oldBuffer, 0, oldBytesRead, oldBuffer, 0); 
        } 
        hashCalculationWorker.ReportProgress((int)((double)totalBytesRead * 100/streamSize)); 
       } while (bytesRead != 0); 
       e.Result = hashObject.Hash; 
       finalHash = GenerateHex(hashObject.Hash); 
       Invoke(new MethodInvoker(() => 
              { 
               // Get finalHash 
              })); 
       hashObject.Dispose(); 
      } 
     } 
     catch (Exception) 
     { 
     } 


     private HashAlgorithm HashObject 
     {   
      get 
      { 
       if (isMD5Selected) 
       { 
        _hashObject = MD5.Create(); 
        isMD5Selected = false; 
       } 
       else if (isMD4Selected) 
       { 
        _hashObject = MD4.Create(); 
        isMD4Selected = false; 
       } 
       else if (isSHA1Selected) 
       { 
        _hashObject = SHA1.Create(); 
        isSHA1Selected = false; 
       } 
       ... 
       return _hashObject; 
       } 
      } 

在上面的代碼中,foreach語句取決於所選散列算法的數量。它會正確計算第一個選定的散列值,但是在第二個和其他下一個迭代中它會給出錯誤的值。 什麼錯了。有誰能夠幫助我? 非常感謝。

+4

乍一看,你沒有重置你的'_dataStream' ... – 2012-07-12 15:14:58

+1

關閉我的頭頂,你沒有正確地重置你的變量和數據流。 – KingCronus 2012-07-12 15:15:21

+0

@KingCronus每次迭代都需要獲取_dataStream嗎? – 2012-07-12 15:30:24

回答

2

您不重置流,以便您可以通過循環重新讀取每次迭代的內容。您的緩衝區管理邏輯可以被簡化很多,並且需要在finally塊中調用hashObject.Dispose,以便在引發異常時釋放資源。

 streamSize = _dataStream.Length; 
     buffer = new byte[4096]; 
     foreach (var hashObject in from Control ctrl in Controls where ctrl is CheckBox && ((CheckBox)ctrl).Checked select HashObject) 
     { 
      try 
      { 
       // reset stream position, progress 
       _dataStream.Position = 0; 
       _totalBytesRead = 0; 

       do 
       { 
        bytesRead = _dataStream.Read(buffer, 0, buffer.Length); 
        totalBytesRead += bytesRead; 
        if (_dataStream.Position == _dataStream.Length) 
        { 
         hashObject.TransformFinalBlock(buffer, 0, bytesRead); 
        } 
        else 
        { 
         hashObject.TransformBlock(buffer, 0, bytesRead, buffer, 0); 
        } 
        hashCalculationWorker.ReportProgress((int)((double)totalBytesRead * 100/streamSize)); 
       } while (_dataStream.Position < _dataStream.Length); 

       e.Result = hashObject.Hash; 
       finalHash = GenerateHex(hashObject.Hash); 
       Invoke(new MethodInvoker(() => 
              { 
               // Get finalHash 
              })); 
      } 
      finally 
      { 
       hashObject.Dispose(); 
      } 
     } 

更好的解決方案,如果該文件並不大:

這可能是更好的性能,以全部來自流中的數據的讀入緩衝區一次,然後重新使用它:

 if (!String.IsNullOrEmpty(selectedFile)) 
     { 
      buffer = File.ReadAllBytes(selectedFile); 
      streamSize = buffer.Length; 
      selectedFile = string.Empty; 
     } 

     foreach (var hashObject in from Control ctrl in Controls where ctrl is CheckBox && ((CheckBox)ctrl).Checked select HashObject) 
     { 
      int offset = 0; 
      while (buffer.Length - offset >= streamSize) 
      { 
       offset += hashObject.TransformBlock(buffer, offset, streamSize, buffer, offset); 
       hashCalculationWorker.ReportProgress((int)((double)offset * 100/streamSize)); 
      } 

      hashObject.TransformFinalBlock(buffer, offset, buffer.Length - offset); 
      hashCalculationWorker.ReportProgress(100); 

      e.Result = hashObject.Hash; 
      finalHash = GenerateHex(hashObject.Hash); 
      Invoke(new MethodInvoker(() => 
             { 
              // Get finalHash 
             })); 
      hashObject.Dispose(); 
     } 
+0

謝謝。我已經嘗試瞭解決大文件的問題。它工作正常,但每個哈希算法需要很多時間(使用大文件),但如果我將每個迭代分割成方法並逐個調用它們,則只需要第一個方法的時間,也不需要重置_dataStream。但在這種技術中,線數增加了很多時間。 – 2012-07-12 16:10:13

+0

@ M.NasserJavaid您必須以某種方式通過每個散列算法獲取相同的數據。您可以預先加載所有數據一次('File.ReadAllBytes'),或者每次都必須重新讀取它,這意味着重置流。 – 2012-07-12 17:11:52