Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I display the progress of an action from another library on a file?

I'm computing the SHA-512 hash of a very large file using System.Security.Cryptography.SHA512Cng.ComputeHash, and I'd like to show a progress bar for it. How can I check the completion of the method without reimplementing the algorithm?

like image 963
Ry- Avatar asked Jan 27 '26 18:01

Ry-


2 Answers

You can subclass Stream! Here's a ProgressStream that reads from a file:

Public Class ProgressStream
    Inherits FileStream

    Public Event ProgressChanged(sender As ProgressStream, progress As Integer)

    Public Sub New(fileName As String)
        MyBase.New(fileName, FileMode.Open, FileAccess.Read)
    End Sub

    Public ReadOnly Property Progress() As Integer
        Get
            Return CInt(Me.Position / Me.Length * 100)
        End Get
    End Property

    Public Overrides Function Read(array() As Byte, offset As Integer, count As Integer) As Integer
        Read = MyBase.Read(array, offset, count)
        RaiseEvent ProgressChanged(Me, Me.Progress)
    End Function
End Class

Just handle the ProgressChanged event.

The same method applies to all other types of streams, and you can also use it for certain other long-running tasks that read a file as required instead of all at once.

like image 151
Ry- Avatar answered Jan 30 '26 10:01

Ry-


A common approach is to use the TransformBlock and TransformFinalBlock and compute the hash in chunks. This allows you to not care about the type of stream you are working with, or maybe you want to hash more than one stream (say all the files in a directory).

Here's a little example:

Using stream As New FileStream("C:\somefile.dat", FileMode.Open),
      hash As New SHA512Cng()
    Const BUFFER_SIZE As Integer = 2048
    Dim buffer(BufferSize - 1) As Byte
    Dim bytesRead As Integer

    Do
        bytesRead = stream.Read(buffer, 0, BUFFER_SIZE)
        hash.TransformBlock(buffer, 0, bytesRead, buffer, 0)

        Dim percentComplete = stream.Position / stream.Length * 100
        'Handle percentComplete here somehow, perhaps with an event
    Loop While stream.Length - stream.Position > BUFFER_SIZE

    bytesRead = stream.Read(buffer, 0, BUFFER_SIZE) ' read the final block
    hash.TransformFinalBlock(buffer, 0, bytesRead)

    'We're now 100% complete, raise an event with 100% completion
    Dim theHash = hash.Hash 'The final hash values
End Using

The smaller the buffer size, the more fine-grained the result, but possibly at the cost of performance.

like image 42
vcsjones Avatar answered Jan 30 '26 09:01

vcsjones



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!