我正在通过下面提供的代码学习文件的MD5哈希值。但是,随着文件大小的增加,计算也将花费很长时间。我想将此计算反映在进度条对象上,但我不知道。
我想要这样的东西;
progressBar.Value = mD5.ComputedBytes;
progressBar.Maximum = mD5.TotalBytesToCompute;
如何制作?
代码;
public static string getMD5HashFromFile(string fileName)
{
string str = "";
using (MD5 mD5 = MD5.Create())
{
using (FileStream fileStream = File.OpenRead(fileName))
{ str = BitConverter.ToString(mD5.ComputeHash(fileStream)).Replace("-", string.Empty); fileStream.Close(); }
}
return str;
}
答案 0 :(得分:6)
HashAlgorithm
使您能够使用TransformBlock
和TransformFinalBlock
方法对数据块进行哈希处理。另一方面,Stream
类还允许您异步读取大块数据。
考虑到这些事实,您可以创建一种方法来获取流作为输入,然后以块的形式读取流,然后为每个卡盘散列它,并通过计算读取的字节来报告进度(字节进程数)。
ComputeHashAsync
在这里,我为ComputeHashAsync
类创建了HashAlgorithm
扩展方法。它接受:
stream
:输入Stream
以计算哈希。cancellationToken
:可选的CancellationToken
,可用于取消操作progress
:IProgress<long>
的可选实例,用于接收进度报告(已处理的字节数)。buggerSize
:用于读取数据的可选缓冲区大小。默认ID 1024 * 1024字节。代码如下:
using System;
using System.IO;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
public static class HashAlgorithmExtensions {
public static async Task<byte[]> ComputeHashAsync(
this HashAlgorithm hashAlgorithm, Stream stream,
CancellationToken cancellationToken = default(CancellationToken),
IProgress<long> progress = null,
int bufferSize = 1024 * 1024) {
byte[] readAheadBuffer, buffer, hash;
int readAheadBytesRead, bytesRead;
long size, totalBytesRead = 0;
size = stream.Length;
readAheadBuffer = new byte[bufferSize];
readAheadBytesRead = await stream.ReadAsync(readAheadBuffer, 0,
readAheadBuffer.Length, cancellationToken);
totalBytesRead += readAheadBytesRead;
do {
bytesRead = readAheadBytesRead;
buffer = readAheadBuffer;
readAheadBuffer = new byte[bufferSize];
readAheadBytesRead = await stream.ReadAsync(readAheadBuffer, 0,
readAheadBuffer.Length, cancellationToken);
totalBytesRead += readAheadBytesRead;
if (readAheadBytesRead == 0)
hashAlgorithm.TransformFinalBlock(buffer, 0, bytesRead);
else
hashAlgorithm.TransformBlock(buffer, 0, bytesRead, buffer, 0);
if (progress != null)
progress.Report(totalBytesRead);
if (cancellationToken.IsCancellationRequested)
cancellationToken.ThrowIfCancellationRequested();
} while (readAheadBytesRead != 0);
return hash = hashAlgorithm.Hash;
}
}
示例1-更新ProgressBar
byte[] bytes;
using (var hash = MD5.Create())
{
using (var fs = new FileStream(f, FileMode.Open))
{
bytes = await hash.ComputeHashAsync(fs,
progress: new Progress<long>(i =>
{
progressBar1.Invoke(new Action(() =>
{
progressBar1.Value = i;
}));
}));
MessageBox.Show(BitConverter.ToString(bytes).Replace("-", string.Empty));
}
}
示例2-1秒后取消任务
try
{
var s = new CancellationTokenSource();
s.CancelAfter(1000);
byte[] bytes;
using (var hash = MD5.Create())
{
using (var fs = new FileStream(f, FileMode.Open))
{
bytes = await hash.ComputeHashAsync(fs,
cancellationToken: s.Token,
progress: new Progress<long>(i =>
{
progressBar1.Invoke(new Action(() =>
{
progressBar1.Value = i;
}));
}));
MessageBox.Show(BitConverter.ToString(bytes).Replace("-", string.Empty));
}
}
}
catch (OperationCanceledException)
{
MessageBox.Show("Operation canceled.");
}
创建大型文件进行测试
var f = Path.Combine(Application.StartupPath, "temp.log");
File.Delete(f);
using (var fs = new FileStream(f, FileMode.Create))
{
fs.Seek(1L * 1024 * 1024 * 1024, SeekOrigin.Begin);
fs.WriteByte(0);
fs.Close();
}
注意:大块计算哈希的实现来自Alexandre Gomes的博客post,然后我更改了代码使其成为async
,并支持{{1} }和CancellationToken
。