我正在为所选文件计算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语句取决于所选哈希算法的数量。它会正确计算第一个选定的哈希值,但在第二个和其他每个下一次迭代时,它会给出错误的值。 怎么了。有谁能够帮我? 非常感谢。
答案 0 :(得分:2)
您没有重置流,因此您可以通过循环重新读取每次迭代的内容。您的缓冲区管理逻辑可以简化很多,并且希望在hashObject.Dispose
块中调用finally
,以便在抛出异常时释放资源。
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();
}