Reputation: 20464
I've written a method that splits a file into little chunks (here) and this is the method that merges those splitted chunks.
The problem I have is with the progress report, the calculation of the ChunkProgress
value is wrong:
It should go from 0% to 100% per each chunk.
How I can fix it?
This is how I'm getting the value:
ChunkProgress = (100I / InputStream.Length) * (SizeWritten - BufferLength)
InputStream.Length = The size in bytes of the current chunk.
SizeWritten = The total amount of written bytes from the first chunk.
BufferLength= The fixed buffer size used to read/write bytes (in this case is 1 megabyte)
This is the relevant code:
''' <summary>
''' Gets or sets the buffer-size to split or merge, in Bytes.
''' Default value is: 1048576 bytes (1 megabyte).
''' </summary>
''' <value>The buffer-size.</value>
Public Property BufferSize As Integer = 1048576I
''' <summary>
''' Merges the specified file.
''' </summary>
''' <param name="InputFile">
''' Indicates the file to merge its chunks.
''' This should be the first chunk file (eg: 'File.Part.01.mkv')
''' </param>
''' <param name="OutputFile">Indicates the output file.</param>
''' <param name="Overwrite">
''' If set to <c>true</c> the chunks will be deleted after a successful merge,
''' otherwise, an exception will be thrown.
''' </param>
''' <exception cref="System.IO.IOException">File already exist</exception>
Public Sub Merge(ByVal InputFile As String,
Optional ByVal OutputFile As String = Nothing,
Optional ByVal Overwrite As Boolean = False,
Optional DeleteChunksAfterMerged As Boolean = False)
If Not File.Exists(InputFile) Then
Throw New FileNotFoundException("The specified file doesn't exists.", InputFile)
Exit Sub
ElseIf Not Overwrite AndAlso File.Exists(OutputFile) Then
Throw New IOException(String.Format("File already exist: {0}", OutputFile))
Exit Sub
End If
' The progress event arguments.
Dim ProgressArguments As MergeProgressChangedArgs
' FileInfo instance of the input chunk file.
Dim fInfo As New FileInfo(InputFile)
' Get the filename without extension.
Dim Filename As String = Path.GetFileNameWithoutExtension(fInfo.FullName)
' Remove the chunk enumeration from the filename.
Filename = Filename.Substring(0I, Filename.LastIndexOf("."c))
' TSet the pattern to find the chunk files to merge.
Dim ChunkPatternSearch As String =
Filename & ".*" & If(Not String.IsNullOrEmpty(fInfo.Extension), fInfo.Extension, "")
' Retrieve all the splitted files to merge them.
Dim Chunks As IEnumerable(Of FileInfo) =
From Chunk As String In
Directory.GetFiles(fInfo.DirectoryName, ChunkPatternSearch, SearchOption.TopDirectoryOnly)
Select New FileInfo(Chunk)
' The total filesize to merge, in bytes.
Dim TotalSize As Long =
(From Chunk As FileInfo In Chunks Select Chunk.Length).Sum
' The remaining size to calculate the percentage, in bytes.
Dim SizeRemaining As Long = TotalSize
' Counts the length of the current chunk file to calculate the percentage, in bytes.
Dim SizeWritten As Long = 0L
' The buffer to read data and merge the chunks.
Dim Buffer As Byte() = New Byte() {}
' The buffer length.
Dim BufferLength As Integer = Me.BufferSize
' The total amount of chunks to merge.
Dim ChunkCount As Integer = Chunks.Count
' Keeps track of the current chunk.
Dim ChunkIndex As Integer = 0I
' Keeps track of the total percentage done.
Dim TotalProgress As Double = 0.0R
' Keeps track of the current chunk percentage done.
Dim ChunkProgress As Double = 0.0R
' Create the output file to merge the chunks inside.
Using OutputStream As New FileStream(OutputFile, FileMode.Create)
Using BinaryWriter As New BinaryWriter(OutputStream)
' Iterate the chunks.
For Each Chunk As FileInfo In Chunks
' Open the chunk to start reading bytes.
Using InputStream As New FileStream(Chunk.FullName, FileMode.Open)
Using BinaryReader As New BinaryReader(InputStream)
' Read until reached the end-bytes of the chunk file.
While (InputStream.Position < InputStream.Length)
' Read bytes from the chunk file (BufferSize byte-length).
Buffer = BinaryReader.ReadBytes(BufferLength)
' Write those bytes in the output file.
BinaryWriter.Write(Buffer)
' Increment the bytes-written counter.
SizeWritten += Buffer.Count
' Decrease the bytes-remaining counter.
SizeRemaining -= Buffer.Count
TotalProgress = (TotalSize - SizeRemaining) * (100I / TotalSize)
ChunkProgress = (100I / InputStream.Length) * (SizeWritten - BufferLength)
' (100I / InputStream.Length) * (SizeWritten - BufferLength)
' Set the progress event-arguments.
ProgressArguments = New MergeProgressChangedArgs(
TotalProgress:=TotalProgress,
ChunkProgress:=ChunkProgress,
ChunksToMerge:=ChunkCount,
ChunksMerged:=ChunkIndex)
' Report the progress.
RaiseEvent MergeProgressChanged(Me, ProgressArguments)
End While ' (InputStream.Position < InputStream.Length)
ChunkIndex += 1I 'Increment the chunk file counter.
End Using ' BinaryReader
End Using ' InputStream
Next Chunk
OutputStream.Flush()
End Using ' BinaryWriter
End Using ' OutputStream
If DeleteChunksAfterMerged Then ' Delethe the chunk files.
For Each Chunk As FileInfo In Chunks
File.Delete(Chunk.FullName)
Next Chunk
End If ' DeleteChunksAfterMerged
End Sub
Upvotes: 0
Views: 43
Reputation: 38875
You need this to calc the percentage for the entire file:
' Increment the bytes-written counter.
SizeWritten += Buffer.Count
But it doesnt have any role in reporting the chunk progress. If you look at the GIF, you'll see it tips over to 100% right at the moment it starts writing chunk #2, then again to 200% when you start to do Chunk 3. To fix it, you need a new ChunkBytesWritten type var:
' Increment the bytes-written counter.
SizeWritten += Buffer.Count
ChunkBytes+= Buffer.Count
Then reset it when the ChunkIndex changes:
ChunkIndex += 1
ChunkBytes = 0
The calc then should be:
ChunkProgress = (100I / InputStream.Length) * (ChunkBytes - BufferLength)
Upvotes: 2