Report Hash Progress












1















I am learning the MD5 hash values of the files through the code I have provided below. However, as the file size grows, the calculation takes a long time as well. I want to reflect this calculation on a progress bar object, but I have no idea.



I want something like this;



progressBar.Value = mD5.ComputedBytes;
progressBar.Maximum = mD5.TotalBytesToCompute;


How to make this?



Code;



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;
}









share|improve this question

























  • It's worth noting (from the MD5 Wikipedia article: en.wikipedia.org/wiki/MD5) that "The CMU Software Engineering Institute considers MD5 essentially 'cryptographically broken and unsuitable for further use'". You won't be able to show "progress" unless you can break the operation up into chunks (for example, if you were hashing 5 files, you could show 20% progress after each file). You can pop up an indefinite progress bar to show that work is happening, but you really can't show specific progress

    – Flydog57
    Dec 28 '18 at 23:57






  • 1





    HashAlgorithm gives you the ability to hash data in chunks using TransformBlock and TransformFinalBlock methods. In the other hand, Stream class also allows you to read data in chunks asynchronously. Considering these facts, you can create a method to get a stream as input and then read stream in chunks and then for each chuck hash it and report the progress (percentage for example) by calculating bytes read.

    – Reza Aghaei
    Dec 29 '18 at 2:15






  • 1





    The solution is not limited to MD5, so you can use it for other hash algorithms as well.

    – Reza Aghaei
    Dec 29 '18 at 11:12
















1















I am learning the MD5 hash values of the files through the code I have provided below. However, as the file size grows, the calculation takes a long time as well. I want to reflect this calculation on a progress bar object, but I have no idea.



I want something like this;



progressBar.Value = mD5.ComputedBytes;
progressBar.Maximum = mD5.TotalBytesToCompute;


How to make this?



Code;



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;
}









share|improve this question

























  • It's worth noting (from the MD5 Wikipedia article: en.wikipedia.org/wiki/MD5) that "The CMU Software Engineering Institute considers MD5 essentially 'cryptographically broken and unsuitable for further use'". You won't be able to show "progress" unless you can break the operation up into chunks (for example, if you were hashing 5 files, you could show 20% progress after each file). You can pop up an indefinite progress bar to show that work is happening, but you really can't show specific progress

    – Flydog57
    Dec 28 '18 at 23:57






  • 1





    HashAlgorithm gives you the ability to hash data in chunks using TransformBlock and TransformFinalBlock methods. In the other hand, Stream class also allows you to read data in chunks asynchronously. Considering these facts, you can create a method to get a stream as input and then read stream in chunks and then for each chuck hash it and report the progress (percentage for example) by calculating bytes read.

    – Reza Aghaei
    Dec 29 '18 at 2:15






  • 1





    The solution is not limited to MD5, so you can use it for other hash algorithms as well.

    – Reza Aghaei
    Dec 29 '18 at 11:12














1












1








1


2






I am learning the MD5 hash values of the files through the code I have provided below. However, as the file size grows, the calculation takes a long time as well. I want to reflect this calculation on a progress bar object, but I have no idea.



I want something like this;



progressBar.Value = mD5.ComputedBytes;
progressBar.Maximum = mD5.TotalBytesToCompute;


How to make this?



Code;



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;
}









share|improve this question
















I am learning the MD5 hash values of the files through the code I have provided below. However, as the file size grows, the calculation takes a long time as well. I want to reflect this calculation on a progress bar object, but I have no idea.



I want something like this;



progressBar.Value = mD5.ComputedBytes;
progressBar.Maximum = mD5.TotalBytesToCompute;


How to make this?



Code;



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;
}






c# .net winforms hash md5






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Dec 29 '18 at 15:27









Reza Aghaei

65.3k853158




65.3k853158










asked Dec 28 '18 at 23:27









Kelly BaileyKelly Bailey

226




226













  • It's worth noting (from the MD5 Wikipedia article: en.wikipedia.org/wiki/MD5) that "The CMU Software Engineering Institute considers MD5 essentially 'cryptographically broken and unsuitable for further use'". You won't be able to show "progress" unless you can break the operation up into chunks (for example, if you were hashing 5 files, you could show 20% progress after each file). You can pop up an indefinite progress bar to show that work is happening, but you really can't show specific progress

    – Flydog57
    Dec 28 '18 at 23:57






  • 1





    HashAlgorithm gives you the ability to hash data in chunks using TransformBlock and TransformFinalBlock methods. In the other hand, Stream class also allows you to read data in chunks asynchronously. Considering these facts, you can create a method to get a stream as input and then read stream in chunks and then for each chuck hash it and report the progress (percentage for example) by calculating bytes read.

    – Reza Aghaei
    Dec 29 '18 at 2:15






  • 1





    The solution is not limited to MD5, so you can use it for other hash algorithms as well.

    – Reza Aghaei
    Dec 29 '18 at 11:12



















  • It's worth noting (from the MD5 Wikipedia article: en.wikipedia.org/wiki/MD5) that "The CMU Software Engineering Institute considers MD5 essentially 'cryptographically broken and unsuitable for further use'". You won't be able to show "progress" unless you can break the operation up into chunks (for example, if you were hashing 5 files, you could show 20% progress after each file). You can pop up an indefinite progress bar to show that work is happening, but you really can't show specific progress

    – Flydog57
    Dec 28 '18 at 23:57






  • 1





    HashAlgorithm gives you the ability to hash data in chunks using TransformBlock and TransformFinalBlock methods. In the other hand, Stream class also allows you to read data in chunks asynchronously. Considering these facts, you can create a method to get a stream as input and then read stream in chunks and then for each chuck hash it and report the progress (percentage for example) by calculating bytes read.

    – Reza Aghaei
    Dec 29 '18 at 2:15






  • 1





    The solution is not limited to MD5, so you can use it for other hash algorithms as well.

    – Reza Aghaei
    Dec 29 '18 at 11:12

















It's worth noting (from the MD5 Wikipedia article: en.wikipedia.org/wiki/MD5) that "The CMU Software Engineering Institute considers MD5 essentially 'cryptographically broken and unsuitable for further use'". You won't be able to show "progress" unless you can break the operation up into chunks (for example, if you were hashing 5 files, you could show 20% progress after each file). You can pop up an indefinite progress bar to show that work is happening, but you really can't show specific progress

– Flydog57
Dec 28 '18 at 23:57





It's worth noting (from the MD5 Wikipedia article: en.wikipedia.org/wiki/MD5) that "The CMU Software Engineering Institute considers MD5 essentially 'cryptographically broken and unsuitable for further use'". You won't be able to show "progress" unless you can break the operation up into chunks (for example, if you were hashing 5 files, you could show 20% progress after each file). You can pop up an indefinite progress bar to show that work is happening, but you really can't show specific progress

– Flydog57
Dec 28 '18 at 23:57




1




1





HashAlgorithm gives you the ability to hash data in chunks using TransformBlock and TransformFinalBlock methods. In the other hand, Stream class also allows you to read data in chunks asynchronously. Considering these facts, you can create a method to get a stream as input and then read stream in chunks and then for each chuck hash it and report the progress (percentage for example) by calculating bytes read.

– Reza Aghaei
Dec 29 '18 at 2:15





HashAlgorithm gives you the ability to hash data in chunks using TransformBlock and TransformFinalBlock methods. In the other hand, Stream class also allows you to read data in chunks asynchronously. Considering these facts, you can create a method to get a stream as input and then read stream in chunks and then for each chuck hash it and report the progress (percentage for example) by calculating bytes read.

– Reza Aghaei
Dec 29 '18 at 2:15




1




1





The solution is not limited to MD5, so you can use it for other hash algorithms as well.

– Reza Aghaei
Dec 29 '18 at 11:12





The solution is not limited to MD5, so you can use it for other hash algorithms as well.

– Reza Aghaei
Dec 29 '18 at 11:12












1 Answer
1






active

oldest

votes


















6














HashAlgorithm gives you the ability to hash data in chunks using TransformBlock and TransformFinalBlock methods. In the other hand, Stream class also allows you to read data in chunks asynchronously.



Considering these facts, you can create a method to get a stream as input and then read stream in chunks and then for each chuck hash it and report the progress (number of bytes processes) by calculating bytes read.



ComputeHashAsync



Here I've created a ComputeHashAsync extension method for HashAlgorithm class. It accepts:





  • stream: input Stream to compute hash.


  • cancellationToken: an optional CancellationToken which can be used to cancel the operation


  • progress: an optional instance of IProgress<long> which receives the progress report (number of bytes processed).


  • buggerSize: an optional buffer size for reading data. The default id 1024*1024 bytes.


Here is the code:



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;
}
}


Example 1 - Update 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));
}
}


Example 2 - Cancelling task after 1 second



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.");
}


Creating a large file for test



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();
}




Note: The implementation of computing hash in chunks, is taken from a blog post by Alexandre Gomes, then I changed the code to make it async and support CancellationToken and IProgress<long>.






share|improve this answer


























  • Hi, first of all, thank you very much for your reply. I'm not sure exactly how to use this code. Could you help me a bit? I created a "Hash.cs" named class for the first code and placed the lines of code in the class, but some lines seemed to be incorrect.

    – Kelly Bailey
    Dec 29 '18 at 14:05











  • Hi, you're welcome. About using the code, just create an empty .cs code file and then copy my code in the file. Then everything should be fine and wherever you create an instance of your hash algorithm like md5, it will have a ComputeHashAsync method.

    – Reza Aghaei
    Dec 29 '18 at 14:11











  • This is how Extension Methods work in C#.

    – Reza Aghaei
    Dec 29 '18 at 14:13






  • 1





    .NET Framework >= 4.5

    – Reza Aghaei
    Dec 29 '18 at 14:48






  • 1





    Hello! I'm not sure, but passing fs.Length to the Invoke is not good idea, because it may be accessed while the fs is closed. Instead, put it in a variable and pass the variable.

    – Reza Aghaei
    Dec 29 '18 at 19:36













Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53965380%2freport-hash-progress%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









6














HashAlgorithm gives you the ability to hash data in chunks using TransformBlock and TransformFinalBlock methods. In the other hand, Stream class also allows you to read data in chunks asynchronously.



Considering these facts, you can create a method to get a stream as input and then read stream in chunks and then for each chuck hash it and report the progress (number of bytes processes) by calculating bytes read.



ComputeHashAsync



Here I've created a ComputeHashAsync extension method for HashAlgorithm class. It accepts:





  • stream: input Stream to compute hash.


  • cancellationToken: an optional CancellationToken which can be used to cancel the operation


  • progress: an optional instance of IProgress<long> which receives the progress report (number of bytes processed).


  • buggerSize: an optional buffer size for reading data. The default id 1024*1024 bytes.


Here is the code:



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;
}
}


Example 1 - Update 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));
}
}


Example 2 - Cancelling task after 1 second



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.");
}


Creating a large file for test



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();
}




Note: The implementation of computing hash in chunks, is taken from a blog post by Alexandre Gomes, then I changed the code to make it async and support CancellationToken and IProgress<long>.






share|improve this answer


























  • Hi, first of all, thank you very much for your reply. I'm not sure exactly how to use this code. Could you help me a bit? I created a "Hash.cs" named class for the first code and placed the lines of code in the class, but some lines seemed to be incorrect.

    – Kelly Bailey
    Dec 29 '18 at 14:05











  • Hi, you're welcome. About using the code, just create an empty .cs code file and then copy my code in the file. Then everything should be fine and wherever you create an instance of your hash algorithm like md5, it will have a ComputeHashAsync method.

    – Reza Aghaei
    Dec 29 '18 at 14:11











  • This is how Extension Methods work in C#.

    – Reza Aghaei
    Dec 29 '18 at 14:13






  • 1





    .NET Framework >= 4.5

    – Reza Aghaei
    Dec 29 '18 at 14:48






  • 1





    Hello! I'm not sure, but passing fs.Length to the Invoke is not good idea, because it may be accessed while the fs is closed. Instead, put it in a variable and pass the variable.

    – Reza Aghaei
    Dec 29 '18 at 19:36


















6














HashAlgorithm gives you the ability to hash data in chunks using TransformBlock and TransformFinalBlock methods. In the other hand, Stream class also allows you to read data in chunks asynchronously.



Considering these facts, you can create a method to get a stream as input and then read stream in chunks and then for each chuck hash it and report the progress (number of bytes processes) by calculating bytes read.



ComputeHashAsync



Here I've created a ComputeHashAsync extension method for HashAlgorithm class. It accepts:





  • stream: input Stream to compute hash.


  • cancellationToken: an optional CancellationToken which can be used to cancel the operation


  • progress: an optional instance of IProgress<long> which receives the progress report (number of bytes processed).


  • buggerSize: an optional buffer size for reading data. The default id 1024*1024 bytes.


Here is the code:



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;
}
}


Example 1 - Update 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));
}
}


Example 2 - Cancelling task after 1 second



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.");
}


Creating a large file for test



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();
}




Note: The implementation of computing hash in chunks, is taken from a blog post by Alexandre Gomes, then I changed the code to make it async and support CancellationToken and IProgress<long>.






share|improve this answer


























  • Hi, first of all, thank you very much for your reply. I'm not sure exactly how to use this code. Could you help me a bit? I created a "Hash.cs" named class for the first code and placed the lines of code in the class, but some lines seemed to be incorrect.

    – Kelly Bailey
    Dec 29 '18 at 14:05











  • Hi, you're welcome. About using the code, just create an empty .cs code file and then copy my code in the file. Then everything should be fine and wherever you create an instance of your hash algorithm like md5, it will have a ComputeHashAsync method.

    – Reza Aghaei
    Dec 29 '18 at 14:11











  • This is how Extension Methods work in C#.

    – Reza Aghaei
    Dec 29 '18 at 14:13






  • 1





    .NET Framework >= 4.5

    – Reza Aghaei
    Dec 29 '18 at 14:48






  • 1





    Hello! I'm not sure, but passing fs.Length to the Invoke is not good idea, because it may be accessed while the fs is closed. Instead, put it in a variable and pass the variable.

    – Reza Aghaei
    Dec 29 '18 at 19:36
















6












6








6







HashAlgorithm gives you the ability to hash data in chunks using TransformBlock and TransformFinalBlock methods. In the other hand, Stream class also allows you to read data in chunks asynchronously.



Considering these facts, you can create a method to get a stream as input and then read stream in chunks and then for each chuck hash it and report the progress (number of bytes processes) by calculating bytes read.



ComputeHashAsync



Here I've created a ComputeHashAsync extension method for HashAlgorithm class. It accepts:





  • stream: input Stream to compute hash.


  • cancellationToken: an optional CancellationToken which can be used to cancel the operation


  • progress: an optional instance of IProgress<long> which receives the progress report (number of bytes processed).


  • buggerSize: an optional buffer size for reading data. The default id 1024*1024 bytes.


Here is the code:



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;
}
}


Example 1 - Update 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));
}
}


Example 2 - Cancelling task after 1 second



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.");
}


Creating a large file for test



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();
}




Note: The implementation of computing hash in chunks, is taken from a blog post by Alexandre Gomes, then I changed the code to make it async and support CancellationToken and IProgress<long>.






share|improve this answer















HashAlgorithm gives you the ability to hash data in chunks using TransformBlock and TransformFinalBlock methods. In the other hand, Stream class also allows you to read data in chunks asynchronously.



Considering these facts, you can create a method to get a stream as input and then read stream in chunks and then for each chuck hash it and report the progress (number of bytes processes) by calculating bytes read.



ComputeHashAsync



Here I've created a ComputeHashAsync extension method for HashAlgorithm class. It accepts:





  • stream: input Stream to compute hash.


  • cancellationToken: an optional CancellationToken which can be used to cancel the operation


  • progress: an optional instance of IProgress<long> which receives the progress report (number of bytes processed).


  • buggerSize: an optional buffer size for reading data. The default id 1024*1024 bytes.


Here is the code:



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;
}
}


Example 1 - Update 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));
}
}


Example 2 - Cancelling task after 1 second



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.");
}


Creating a large file for test



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();
}




Note: The implementation of computing hash in chunks, is taken from a blog post by Alexandre Gomes, then I changed the code to make it async and support CancellationToken and IProgress<long>.







share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 29 '18 at 17:29









Ahmed Abdelhameed

5,58882046




5,58882046










answered Dec 29 '18 at 2:08









Reza AghaeiReza Aghaei

65.3k853158




65.3k853158













  • Hi, first of all, thank you very much for your reply. I'm not sure exactly how to use this code. Could you help me a bit? I created a "Hash.cs" named class for the first code and placed the lines of code in the class, but some lines seemed to be incorrect.

    – Kelly Bailey
    Dec 29 '18 at 14:05











  • Hi, you're welcome. About using the code, just create an empty .cs code file and then copy my code in the file. Then everything should be fine and wherever you create an instance of your hash algorithm like md5, it will have a ComputeHashAsync method.

    – Reza Aghaei
    Dec 29 '18 at 14:11











  • This is how Extension Methods work in C#.

    – Reza Aghaei
    Dec 29 '18 at 14:13






  • 1





    .NET Framework >= 4.5

    – Reza Aghaei
    Dec 29 '18 at 14:48






  • 1





    Hello! I'm not sure, but passing fs.Length to the Invoke is not good idea, because it may be accessed while the fs is closed. Instead, put it in a variable and pass the variable.

    – Reza Aghaei
    Dec 29 '18 at 19:36





















  • Hi, first of all, thank you very much for your reply. I'm not sure exactly how to use this code. Could you help me a bit? I created a "Hash.cs" named class for the first code and placed the lines of code in the class, but some lines seemed to be incorrect.

    – Kelly Bailey
    Dec 29 '18 at 14:05











  • Hi, you're welcome. About using the code, just create an empty .cs code file and then copy my code in the file. Then everything should be fine and wherever you create an instance of your hash algorithm like md5, it will have a ComputeHashAsync method.

    – Reza Aghaei
    Dec 29 '18 at 14:11











  • This is how Extension Methods work in C#.

    – Reza Aghaei
    Dec 29 '18 at 14:13






  • 1





    .NET Framework >= 4.5

    – Reza Aghaei
    Dec 29 '18 at 14:48






  • 1





    Hello! I'm not sure, but passing fs.Length to the Invoke is not good idea, because it may be accessed while the fs is closed. Instead, put it in a variable and pass the variable.

    – Reza Aghaei
    Dec 29 '18 at 19:36



















Hi, first of all, thank you very much for your reply. I'm not sure exactly how to use this code. Could you help me a bit? I created a "Hash.cs" named class for the first code and placed the lines of code in the class, but some lines seemed to be incorrect.

– Kelly Bailey
Dec 29 '18 at 14:05





Hi, first of all, thank you very much for your reply. I'm not sure exactly how to use this code. Could you help me a bit? I created a "Hash.cs" named class for the first code and placed the lines of code in the class, but some lines seemed to be incorrect.

– Kelly Bailey
Dec 29 '18 at 14:05













Hi, you're welcome. About using the code, just create an empty .cs code file and then copy my code in the file. Then everything should be fine and wherever you create an instance of your hash algorithm like md5, it will have a ComputeHashAsync method.

– Reza Aghaei
Dec 29 '18 at 14:11





Hi, you're welcome. About using the code, just create an empty .cs code file and then copy my code in the file. Then everything should be fine and wherever you create an instance of your hash algorithm like md5, it will have a ComputeHashAsync method.

– Reza Aghaei
Dec 29 '18 at 14:11













This is how Extension Methods work in C#.

– Reza Aghaei
Dec 29 '18 at 14:13





This is how Extension Methods work in C#.

– Reza Aghaei
Dec 29 '18 at 14:13




1




1





.NET Framework >= 4.5

– Reza Aghaei
Dec 29 '18 at 14:48





.NET Framework >= 4.5

– Reza Aghaei
Dec 29 '18 at 14:48




1




1





Hello! I'm not sure, but passing fs.Length to the Invoke is not good idea, because it may be accessed while the fs is closed. Instead, put it in a variable and pass the variable.

– Reza Aghaei
Dec 29 '18 at 19:36







Hello! I'm not sure, but passing fs.Length to the Invoke is not good idea, because it may be accessed while the fs is closed. Instead, put it in a variable and pass the variable.

– Reza Aghaei
Dec 29 '18 at 19:36




















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53965380%2freport-hash-progress%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Monofisismo

Angular Downloading a file using contenturl with Basic Authentication

Olmecas