【问题标题】:Hash calculation in C#C#中的哈希计算
【发布时间】:2012-07-12 09:19:45
【问题描述】:

我正在计算所选文件的 MD5、MD4、SHA1、SHA256、SHA512、RIPEMD160 等。 我创建了以下算法,但它有问题。

        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 语句取决于选择的哈希算法的数量。它正确计算了第一个选择的哈希值,但在第二次和其他下一次迭代中它给出了错误的值。 怎么了。有谁能够帮我? 提前非常感谢。

【问题讨论】:

  • 乍一看,您并没有重置您的_dataStream...
  • 在我看来,您没有正确重置变量和数据流。
  • @KingCronus 每次迭代都需要获取_dataStream吗?
  • 重置 _dataStream 下一次迭代需要太多时间。
  • @Ic 每次迭代都需要获取 _dataStream 吗?在重置 _dataStream 时,下一次迭代需要太多时间。我已经检查过了。当我在没有 foreach 语句的情况下重复使用它时,它工作正常。

标签: c# hash md5 abstract-class sha1


【解决方案1】:

您不会重置流,以便您可以在循环中的每次迭代中重新读取其内容。您的缓冲区管理逻辑可以大大简化,最好在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();  
        }  

【讨论】:

  • 谢谢。我已经尝试过您的大文件解决方案。它可以正常工作,但是在每个哈希算法上都需要很长时间(使用大文件),但是如果我将每个迭代拆分为方法并一个一个地调用它们,那么它只需要第一个方法的时间,也不需要重置 _dataStream。但是在这种技术中,行数增加了很多倍。
  • @M.NasserJavaid 您必须以某种方式通过每个哈希算法获得相同的数据。您可以预加载所有数据一次 (File.ReadAllBytes),也可以每次都重新读取,这意味着重置流。
猜你喜欢
  • 2016-06-23
  • 2016-08-03
  • 1970-01-01
  • 2014-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-23
  • 2017-02-04
相关资源
最近更新 更多