Сообщить о прогрессе хэша - PullRequest
0 голосов
/ 29 декабря 2018

Я изучаю хэш-значения файлов 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;
}

1 Ответ

0 голосов
/ 29 декабря 2018

HashAlgorithm дает вам возможность хэшировать данные кусками, используя методы TransformBlock и TransformFinalBlock.С другой стороны, класс Stream также позволяет асинхронно читать данные порциями.

Принимая во внимание эти факты, вы можете создать метод для получения потока в качестве входных данных, а затем для чтения потока в чанках, а затем для каждого хака в хаке и для отчета о ходе выполнения (число процессов в байтах) путем вычисления прочитанных байтов.

ComputeHashAsync

Здесь я создал ComputeHashAsync метод расширения для HashAlgorithm класса.Он принимает:

  • stream: ввод Stream для вычисления хэша.
  • cancellationToken: необязательный CancellationToken, который можно использовать для отмены операции
  • progress: необязательный экземпляр IProgress<long>, который получает отчет о ходе выполнения (количество обработанных байтов).
  • buggerSize: необязательный размер буфера для чтения данных.Идентификатор по умолчанию 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();
}

Примечание: Реализация вычислительного хэша в чанках взята из блога post Александра Гомеса, затем я изменил код, чтобы сделать его async и поддержкой CancellationToken и IProgress<long>.

...