在此文件操作中正确报告进度?

时间:2014-08-11 17:56:25

标签: .net vb.net file math progress

此方法将文件拆分为块,我想报告剩余块的进度(百分比)以及完成任务的剩余字节总数。

我把算术操作搞砸了,有人可以帮助我吗?

请在代码中注明我需要报告进度的说明,我使用标签进行测试,我会将值保存在变量中:

Label1.Text = ...

以下是方法:

    Public Sub SplitFile(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)

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

       ' The buffer to read data and write the chunks.
       Dim Buffer As Byte() = New Byte() {}

       ' The buffer length.
       Dim BufferSize As Integer = 1048576I ' 1048576 = 1 mb | 33554432 = 32 mb | 67108864 = 64 mb

       ' Counts the length of the current chunk file.
       Dim BytesWritten As Long = 0L

       ' 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),
                      IO.Path.Combine(fInfo.DirectoryName, IO.Path.GetFileNameWithoutExtension(fInfo.Name)),
                      IO.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 < BufferSize Then
           BufferSize = 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 IO.File.Exists(ChunkFile) Then

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

               End If ' IO.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 IO.FileStream(fInfo.FullName, IO.FileMode.Open)

           Using BinaryReader As New IO.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.
                   BytesWritten = 0L

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

                       Using BinaryWriter As New IO.BinaryWriter(OutputStream)

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

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

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

                               ' Increment the size counter.
                               BytesWritten += Buffer.Count

                               ' Use the written bytes of this chunk to calculate the total remaining bytes of the operation (not only for this chunk)...
                               ' Label1.Text = CDbl((100L / ChunkSize) * BytesWritten) / (ChunkIndex / ChunkCount) '/ fInfo.Length
                               Application.DoEvents()

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

                           OutputStream.Flush()

                       End Using ' BinaryWriter

                   End Using ' OutputStream

                   ChunkIndex += 1I 'Increment file counter

                   ' Report progress of remaining chunks...
                   ' Label1.Text = CDbl((100I / ChunkCount) * (ChunkIndex))

               End While ' InputStream.Position < InputStream.Length

           End Using ' BinaryReader

       End Using ' InputStream

   End Sub
  

更新:

有了这个,我就可以在创建一个块时打印进度,但是它可以很好地进行,但我们必须将每个块的文件拆分为3 GB,然后我只能报告一些进度变化完成创建块的时间:

Debug.WriteLine(((ChunkIndex) / ChunkCount) * 100I)

这就是我在每个块中写入字节时尝试编写进度报告的原因,这样我可以每秒快速报告进度变化,请注意上面代码中的这部分,这里是我的地方需要帮助:

' Use the written bytes of this chunk to calculate the total remaining bytes of the operation (not only for this chunk)...
' Label1.Text = CDbl((100L / ChunkSize) * BytesWritten) / (ChunkIndex / ChunkCount) '/ fInfo.Length

1 个答案:

答案 0 :(得分:1)

一些风格的东西:

以小写字母命名局部变量通常是个好主意。它使您更容易阅读和遵循您的代码。当它们以大写字母开头时,它们会被误认为是方法名称(也许这只是我的偏好)

没有必要使用IL后缀数字。声明变量时,编译器将在您明确指定类型时知道要执行的操作。

回答你的问题:

如果我理解您只想要更精细的进度数据,只需声明一个变量来保存文件的总大小,并减去每个分块缓冲区操作后写入的字节数。添加此声明:

    Dim bytesRemaining = fInfo.Length

然后从此处更改While循环:

While (BytesWritten < ChunkSize) AndAlso (InputStream.Position < InputStream.Length)

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

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

    ' Increment the size counter.
    BytesWritten += Buffer.Count

    ' Use the written bytes of this chunk to calculate the total remaining bytes of the operation (not only for this chunk)...
    ' Label1.Text = CDbl((100L / ChunkSize) * BytesWritten) / (ChunkIndex / ChunkCount) '/ fInfo.Length
    Application.DoEvents()

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

对此:

While (BytesWritten < ChunkSize) AndAlso (InputStream.Position < InputStream.Length)

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

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

    ' Increment the size counter.
    BytesWritten += Buffer.Count

    bytesRemaining -= Buffer.Count

    ' Use the written bytes of this chunk to calculate the total remaining bytes of the operation (not only for this chunk)...

    If bytesRemaining > 0 Then
        Label1.Text = (bytesRemaining / fInfo.Length) * 100
    End If

    Application.DoEvents()

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

您必须按照您希望的百分比格式。

另外,请注意我没有针对每种可能的情况对此进行测试。可能在最后一个文件中出现了一些疯狂的问题,当它发生时你必须解决这个问题。