【问题标题】:Report progress properly in this file operation?在此文件操作中正确报告进度?
【发布时间】:2014-08-11 17:56:24
【问题描述】:

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

我的算术运算搞砸了,有人可以帮助我吗?

请注意代码中我需要报告进度的说明,我使用标签只是为了测试,我会将值保留在变量中:

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

【问题讨论】:

  • 那里有很多代码...实际的问题是什么?你有错误吗?
  • @Brandon,在问题中(不是代码的部分)我已经解释了这个问题,我试图得到一个百分比,我已经解释了代码中的指令在哪里。
  • @Plutonix 感谢您提供的信息,这有助于我打印进度,但是在将字节添加到块中时,我正在处理另一个(更精确的)进度,它在代码中,你能帮我解决这个问题?

标签: .net vb.net file math progress


【解决方案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)

您必须按照自己的意愿格式化百分比。

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

【讨论】:

  • 谢谢你的帮助,但在最后一个文件中它给出了一个1144058700,在倒数第二个文件之前它给了我一个1048575900,我真的不明白如何从这些值,它们似乎是错误的,您能否验证您的代码或给我指示以进行值格式化?谢谢你
  • 那是因为我错误地复制了计算。给我一分钟解决它。
  • 我编辑了我的答案,试试吧。此外,我提供的解决方案将为您提供已完成的分块百分比,而不是剩余百分比。删除剩余百分比的 -100。
  • 我认为计算仍然很糟糕,最后一个文件给了我一个infinite,倒数第二个文件给了我一个1098,18312827022,没有-100,而是一个1098增加 100 给我一个 1198,18312827022 我只是想将 10,9 mb 的文件拆分为 1 mb 块,这是代码:SplitFile("C:\test.mp3", 1024 ^ 2, "Test.Part", "mp3", True)
  • 最后一个文件给出了 Infinity,因为它被零除。这就是我说我没有测试所有案例时的意思。我不确定您如何使用我提供的代码,但我成功地将一个 115mb 的文本文件多次拆分为 1024kb 的块,并获得了适当的百分比更新。你正在做一些不同的事情。
猜你喜欢
  • 1970-01-01
  • 2015-01-12
  • 1970-01-01
  • 2015-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多