我正在通过下面提供的代码学习文件的 MD5 哈希值。但是,随着文件大小的增长,计算也需要很长时间。我想在进度条对象上反射(reflect)这个计算,但我不知道。
我想要这样的东西;
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;
}
最佳答案
HashAlgorithm
使您能够使用 TransformBlock
散列数据 block 和 TransformFinalBlock
方法。另一方面, Stream
类还允许您异步读取数据 block 。
考虑到这些事实,您可以创建一种方法来获取流作为输入,然后分块读取流,然后针对每个 chuck 对其进行哈希处理,并通过计算读取的字节数来报告进度(处理的字节数)。
ComputeHashAsync
我在这里创建了一个 ComputeHashAsync
HashAlgorithm
的扩展方法类(class)。它接受:
-
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();
}
<子>
注意:以 block 为单位计算哈希的实现,摘自博客post通过 Alexandre Gomes,然后我更改了代码使其成为 async
并支持CancellationToken
和 IProgress<long>
.
关于c# - 报告哈希进度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53965380/