使用此方法修复进度报告事件 [英] Fix progress report event in this method

查看:72
本文介绍了使用此方法修复进度报告事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试编写一种将文件拆分为较小部分的方法(我称这些部分为块"),我使用1 MB的缓冲区读取/写入块,并报告了操作进度百分比和当前的进度百分比.

I've tried to write a method that splits a file into smaller parts (I call those parts 'chunks'), I use a buffer of 1 MB to read/write the chunks and I'm reporting the operation progress percentage and the current chunk progress percent.

问题是这样的,我有一个6,74 GB的大文件,我将其分割成每个1 GB的块,进度报告按预期方式工作,但最后一个块的进度报告不能达到75, %',因为最后一部分大约是750 mb,而不是1 GB,所以进度仅在最后一块显示高达75%.

The problem is this, I have a big file of 6,74 GB and I will split it into chunks of 1 GB each one, the progress report works as expected but not for the last chunk where the progress up only to 75% 'cause of course the last part is around 750 mb and not 1 GB, then the progress only show up to 75% in the last chunk.

这是我获取百分比的方式,错误的进度是Else块中的ChunkProgress值:

This is how I'm getting the percentages, the wrong progress is the ChunkProgress value in the Else block:

If Not ChunkIndex = ChunkCount Then
    ProgressArguments =
        New SplitProgressChangedArgs(
            TotalProgress:=(TotalSize - SizeRemaining) * (100I / TotalSize),
            ChunkProgress:=(100I / ChunkSize) * (SizeWritten - BufferLength),
            ChunksToCreate:=ChunkCount + 1,
            ChunksCreated:=ChunkIndex)

Else
    ProgressArguments =
        New SplitProgressChangedArgs(
            TotalProgress:=(TotalSize - SizeRemaining) * (100I / TotalSize) - 1.0R,
            ChunkProgress:=(100I / ChunkSize) * (SizeWritten - InputStream.Length),
            ChunksToCreate:=ChunkCount + 1,
            ChunksCreated:=ChunkIndex)

End If

TotalSize =要分割的文件的固定大小,以字节为单位(在这种情况下为6,74 gb)

TotalSize = The fixed size of the file being splitted, in bytes (in this case 6,74 gb)

ChunkSize =块的固定大小,以字节为单位(在这种情况下为1 GB)

ChunkSize = the fixed size of the chunk, in bytes (in this case 1 GB)

SizeRemaining =总剩余大小计数器,以字节为单位(在这种情况下,从6,74 gb到0).

SizeRemaining = The total remaining size counter, in bytes (in this case from 6,74 gb to 0).

SizeWritten =写入的块大小计数器,以字节为单位(在这种情况下,从0到1 GB)

SizeWritten = The chunk size written counter, in bytes (in this case from 0 to 1 GB)

有人可以帮我确定最后一块的百分比吗?

Someone could help me to fix the percentage when writting the last chunk?

这是该类的相关代码:

''' <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>
''' Splits the specified file.
''' </summary>
''' <param name="InputFile">Indicates the file to split.</param>
''' <param name="ChunkSize">Indicates the size of each chunk.</param>
''' <param name="ChunkName">Indicates the name-format for the chunks.</param>
''' <param name="ChunkExt">Indicates the file-extension for the chunks.</param>
''' <param name="Overwrite">
''' If set to <c>true</c> any existing file will be overwritten if needed to create a chunk, 
''' otherwise, an exception will be thrown.
''' </param>
''' <param name="DeleteAfterSplit">If set to <c>true</c> the input file will be deleted after a successful split.</param>
''' <exception cref="System.OverflowException">'ChunkSize' should be smaller than the Filesize.</exception>
''' <exception cref="System.IO.IOException">File already exist</exception>
Public Sub Split(ByVal InputFile As String,
                 ByVal ChunkSize As Long,
                 Optional ByVal ChunkName As String = Nothing,
                 Optional ByVal ChunkExt As String = Nothing,
                 Optional ByVal Overwrite As Boolean = False,
                 Optional ByVal DeleteAfterSplit As Boolean = False)

    ' The progress event arguments.
    Dim ProgressArguments As SplitProgressChangedArgs

    ' FileInfo instance of the input file.
    Dim fInfo As New FileInfo(InputFile)

    ' The total filesize to split, in bytes.
    Dim TotalSize As Long = fInfo.Length

    ' 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 write the chunks.
    Dim Buffer As Byte() = New Byte() {}

    ' The buffer length.
    Dim BufferLength As Integer = Me.BufferSize

    ' The total amount of chunks to create.
    Dim ChunkCount As Integer = CInt(Math.Floor(fInfo.Length / ChunkSize))

    ' Keeps track of the current chunk.
    Dim ChunkIndex As Integer = 0I

    ' A zero-filled string to enumerate the chunk files.
    Dim Zeros As String = String.Empty

    ' The given filename for each chunk.
    Dim ChunkFile As String = String.Empty

    ' The chunk file basename.
    ChunkName = If(String.IsNullOrEmpty(ChunkName),
                   Path.Combine(fInfo.DirectoryName, Path.GetFileNameWithoutExtension(fInfo.Name)),
                   Path.Combine(fInfo.DirectoryName, ChunkName))

    ' The chunk file extension.
    ChunkExt = If(String.IsNullOrEmpty(ChunkExt),
                  fInfo.Extension.Substring(1I),
                  ChunkExt)

    ' If ChunkSize is bigger than filesize then...
    If ChunkSize >= fInfo.Length Then
        Throw New OverflowException("'ChunkSize' should be smaller than the Filesize.")
        Exit Sub

        ' For cases where a chunksize is smaller than the buffersize.
    ElseIf ChunkSize < BufferLength Then
        BufferLength = CInt(ChunkSize)

    End If ' ChunkSize <>...

    ' If not file-overwrite is allowed then...
    If Not Overwrite Then

        For Index As Integer = 0I To (ChunkCount)

            ' Set chunk filename.
            Zeros = New String("0", CStr(ChunkCount).Length - CStr(Index + 1I).Length)
            ChunkFile = String.Format("{0}.{1}.{2}", ChunkName, Zeros & CStr(Index + 1I), ChunkExt)

            ' If chunk file already exists then...
            If File.Exists(ChunkFile) Then

                Throw New IOException(String.Format("File already exist: {0}", ChunkFile))
                Exit Sub

            End If ' File.Exists(ChunkFile)

        Next Index

        Zeros = String.Empty
        ChunkFile = String.Empty

    End If ' Overwrite

    ' Open the file to start reading bytes.
    Using InputStream As New FileStream(fInfo.FullName, FileMode.Open)

        Using BinaryReader As New BinaryReader(InputStream)

            While (InputStream.Position < InputStream.Length)

                ' Set chunk filename.
                Zeros = New String("0", CStr(ChunkCount).Length - CStr(ChunkIndex + 1I).Length)
                ChunkFile = String.Format("{0}.{1}.{2}", ChunkName, Zeros & CStr(ChunkIndex + 1I), ChunkExt)

                ' Reset written byte-length counter.
                SizeWritten = 0L

                ' Create the chunk file to Write the bytes.
                Using OutputStream As New FileStream(ChunkFile, FileMode.Create)

                    Using BinaryWriter As New BinaryWriter(OutputStream)

                        ' Read until reached the end-bytes of the input file.
                        While (SizeWritten < ChunkSize) AndAlso (InputStream.Position < InputStream.Length)

                            ' Read bytes from the original file (BufferSize byte-length).
                            Buffer = BinaryReader.ReadBytes(BufferLength)

                            ' Write those bytes in the chunk file.
                            BinaryWriter.Write(Buffer)

                            ' Increment the bytes-written counter.
                            SizeWritten += Buffer.Count

                            ' Decrease the bytes-remaining counter.
                            SizeRemaining -= Buffer.Count

                            If Not ChunkIndex = ChunkCount Then
                                ProgressArguments =
                                    New SplitProgressChangedArgs(
                                        TotalProgress:=(TotalSize - SizeRemaining) * (100I / TotalSize),
                                        ChunkProgress:=(100I / ChunkSize) * (SizeWritten - BufferLength),
                                        ChunksToCreate:=ChunkCount + 1,
                                        ChunksCreated:=ChunkIndex)

                            Else
                                ProgressArguments =
                                    New SplitProgressChangedArgs(
                                        TotalProgress:=(TotalSize - SizeRemaining) * (100I / TotalSize) - 1.0R,
                                        ChunkProgress:=(100I / ChunkSize) * (SizeWritten - InputStream.Length),
                                        ChunksToCreate:=ChunkCount + 1,
                                        ChunksCreated:=ChunkIndex)

                            End If

                            ' Report the progress.
                            RaiseEvent SplitProgressChanged(Me, ProgressArguments)

                        End While ' (SizeWritten < ChunkSize) AndAlso (InputStream.Position < InputStream.Length)

                        OutputStream.Flush()

                    End Using ' BinaryWriter

                End Using ' OutputStream

                ChunkIndex += 1I 'Increment the chunk file counter.

            End While ' InputStream.Position < InputStream.Length

        End Using ' BinaryReader

    End Using ' InputStream

End Sub

这是一个示例用法:

Splitter.Split(InputFile:="C:\Test.mkv",
               ChunkSize:=1073741824L,
               ChunkName:="Test.Part",
               ChunkExt:="mp3",
               Overwrite:=True,
               DeleteAfterSplit:=False)

推荐答案

进度没有在最后一块正确显示的原因是因为您是根据正常"块大小来计算进度

The reason the progress doesn't show up correctly on the last chunk is because you're calculating progress against the "normal" chunk size

例如(使用简化值):

500 out of 1000 bytes with ChunkSize = 1000
500 / ChunkSize = %
500/1000 = 0.5

如果最后一个块只有750个字节,我们必须除以(thisChunk / ChunkSize)来纠正:

If the last chunk only has 750 bytes, we have to correct by dividing by (thisChunk / ChunkSize):

500 out of 750 bytes with ChunkSize = 1000
500 / ChunkSize / (thisChunk / ChunkSize) = %
500/1000 / (750/1000) = 0.667

Else情况下尝试此操作. (InputStream.Length - SizeWritten)应该获取剩余块的大小:

Try this for the Else case. (InputStream.Length - SizeWritten) should get the size of the remaining chunk:

ProgressArguments =
  New SplitProgressChangedArgs(
  TotalProgress:=(TotalSize - SizeRemaining) * (100I / TotalSize) - 1.0R,
  ChunkProgress:=(100I / ChunkSize) * (SizeWritten - InputStream.Length) / ((InputStream.Length - SizeWritten) / ChunkSize),
  ChunksToCreate:=ChunkCount + 1,
  ChunksCreated:=ChunkIndex)

这篇关于使用此方法修复进度报告事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆