使用filestream停止散列操作

时间:2016-04-18 23:04:43

标签: c# multithreading hash md5 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;
            }
        }
    }

我在一个单独的线程中运行这个耗时的操作。对于非常大的文件,此操作可能需要几秒/分钟。我想要做的是能够从另一个线程停止操作,例如使用" Stop" GUI中的按钮。有什么建议吗?

1 个答案:

答案 0 :(得分:1)

您可以阅读文件部分并将MD5.TransformBlock应用于每个阅读部分。 (注意,最后一部分应该用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;
            }
        }
    }
}