使用文件流停止哈希操作
stop hashing operation using filestream
我正在使用这段代码计算给定输入文件的 MD5 哈希值。
public static String ComputeMD5(String filename)
{
using (var md5 = MD5.Create())
{
try
{
using (var stream = File.OpenRead(filename))
{
return BitConverter.ToString(md5.ComputeHash(stream)).Replace("-", "").ToLower();
}
}
catch (Exception)
{
// File is not accessible, return String.Empty
return String.Empty;
}
}
}
我运行这个耗时的操作在一个单独的线程中。对于非常大的文件,此操作可能需要 seconds/minutes。我想要做的是能够从另一个线程停止操作,例如在 GUI 中使用 "Stop" 按钮。有什么建议吗?
您可以阅读文件部分并应用 MD5.TransformBlock to each read part. (Notice, that last part should be read with MD5.TransformFinalBlock)。
在处理每个块之间,您可以检查是否需要取消,您可以自由使用任何您喜欢的同步原语。
这里是例子,使用 CancellationToken
:
using System;
using System.IO;
using System.Threading;
using System.Security.Cryptography;
namespace Stack
{
class Program
{
static void Main(string[] args)
{
using (var cancellationTokenSource = new CancellationTokenSource())
{
var thread = new Thread(() =>
{
try
{
var hash = CalcHash("D:/Image.iso", cancellationTokenSource.Token);
Console.WriteLine($"Done: hash is {BitConverter.ToString(hash)}");
}
catch (OperationCanceledException)
{
Console.WriteLine("Canceled :(");
}
});
// Start background thread
thread.Start();
Console.WriteLine("Working, press any key to exit");
Console.ReadLine();
cancellationTokenSource.Cancel();
}
Console.WriteLine("Finished");
Console.ReadLine();
}
static byte[] CalcHash(string path, CancellationToken ct)
{
using (var stream = File.OpenRead(path))
using (var md5 = MD5.Create())
{
const int blockSize = 1024 * 1024 * 4;
var buffer = new byte[blockSize];
long offset = 0;
while (true)
{
ct.ThrowIfCancellationRequested();
var read = stream.Read(buffer, 0, blockSize);
if (stream.Position == stream.Length)
{
md5.TransformFinalBlock(buffer, 0, read);
break;
}
offset += md5.TransformBlock(buffer, 0, buffer.Length, buffer, 0);
Console.WriteLine($"Processed {offset * 1.0 / 1024 / 1024} MB so far");
}
return md5.Hash;
}
}
}
}
我正在使用这段代码计算给定输入文件的 MD5 哈希值。
public static String ComputeMD5(String filename)
{
using (var md5 = MD5.Create())
{
try
{
using (var stream = File.OpenRead(filename))
{
return BitConverter.ToString(md5.ComputeHash(stream)).Replace("-", "").ToLower();
}
}
catch (Exception)
{
// File is not accessible, return String.Empty
return String.Empty;
}
}
}
我运行这个耗时的操作在一个单独的线程中。对于非常大的文件,此操作可能需要 seconds/minutes。我想要做的是能够从另一个线程停止操作,例如在 GUI 中使用 "Stop" 按钮。有什么建议吗?
您可以阅读文件部分并应用 MD5.TransformBlock to each read part. (Notice, that last part should be read with MD5.TransformFinalBlock)。 在处理每个块之间,您可以检查是否需要取消,您可以自由使用任何您喜欢的同步原语。
这里是例子,使用 CancellationToken
:
using System;
using System.IO;
using System.Threading;
using System.Security.Cryptography;
namespace Stack
{
class Program
{
static void Main(string[] args)
{
using (var cancellationTokenSource = new CancellationTokenSource())
{
var thread = new Thread(() =>
{
try
{
var hash = CalcHash("D:/Image.iso", cancellationTokenSource.Token);
Console.WriteLine($"Done: hash is {BitConverter.ToString(hash)}");
}
catch (OperationCanceledException)
{
Console.WriteLine("Canceled :(");
}
});
// Start background thread
thread.Start();
Console.WriteLine("Working, press any key to exit");
Console.ReadLine();
cancellationTokenSource.Cancel();
}
Console.WriteLine("Finished");
Console.ReadLine();
}
static byte[] CalcHash(string path, CancellationToken ct)
{
using (var stream = File.OpenRead(path))
using (var md5 = MD5.Create())
{
const int blockSize = 1024 * 1024 * 4;
var buffer = new byte[blockSize];
long offset = 0;
while (true)
{
ct.ThrowIfCancellationRequested();
var read = stream.Read(buffer, 0, blockSize);
if (stream.Position == stream.Length)
{
md5.TransformFinalBlock(buffer, 0, read);
break;
}
offset += md5.TransformBlock(buffer, 0, buffer.Length, buffer, 0);
Console.WriteLine($"Processed {offset * 1.0 / 1024 / 1024} MB so far");
}
return md5.Hash;
}
}
}
}