Adam
Adam

Reputation: 243

Issue correctly calculating time remaining on file copy

I am having issue correctly estimating a realistic 'time remaining' app for a copy app. I am using a Filestream for the copy as the files being copied vary from >1MB to 4GB. I am using percentageTotal here to calculate the current position of the filecopy over all:

  'Loop through each file in the SourceDir
            For Each ChildFile In SourceDir.GetFiles()

                If (worker.CancellationPending = True) Then
                    e.Cancel = True
                End If

                'Calculate data being moved for eta to completion
                Dim filetotalbytes As Double = ChildFile.Length
                filetotalsofarcopied = filetotalbytes + filetotalsofarcopied


                'Display file being copied
                SetLabelText_ThreadSafe(Me.lblStatus, "Copying: " & line & "\" & ChildFile.Name & "")

                'Do the copy
                ChildFile.CopyTo(Path.Combine(DestDir.FullName, ChildFile.Name), True)

                'Contruct Destination and Source Strings
                deststring = DestDir.ToString & "\" & ChildFile.Name
                Dim sourcedirstring As String
                sourcedirstring = SourceDir.ToString & "\" & ChildFile.Name

        Dim CopyStream As New FileStream(sourcedirstring, FileMode.Open, FileAccess.Read)
        Dim NewStream As New FileStream(deststring, FileMode.Append)

        Dim Buffer(4096) As Byte
        Dim BytesRead As Integer
        Dim len As Long = CopyStream.Length - 1

        While CopyStream.Position < len


            BytesRead = CopyStream.Read(Buffer, 0, Buffer.Length)
            NewStream.Write(Buffer, 0, BytesRead)

            percentageTotal = ((NewStream.Length + filetotalsofarcopied) / Overallsize * 100)
            percentageTotal = Decimal.Round(percentageTotal)

            '  SetLabelText_ThreadSafe(Me.lblTotalProgress, "" & percentageTotal & "%")

        End While

        CopyStream.Dispose()
        NewStream.Dispose()

I find that the value of percentageTotal often jumps rather than increases in a liner fashion as I would expect. Can anyone see where I am going wrong here?

Additionally I cannot perfect the logic of the secondsremaining value. It currently shows the copy taking days when initially run before quickly decreasing but obviously not the correct time remaining.

 'Start process snippit
 'Start Button Click config - starts the backgroundworker
Public Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

   'Set start value - label22 is hidden on form1
    Label22.Text = "0"

    'Start timers
    Timer3.Start()
    Timer4.Start()


    'Start background worker
    BackgroundWorker1.WorkerSupportsCancellation = True
    BackgroundWorker1.WorkerReportsProgress = True
    BackgroundWorker1.RunWorkerAsync()

End Sub

UPDATED! And the Timer.Tick code at the end of the form calculating the time remaining:

 Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    byteslastsecond = filetotalsofarcopied
End Sub


'Every tick of Timer4 calculates the time needed to complete the copy.
   Private Sub Timer4_Tick(sender As Object, e As EventArgs) Handles Timer4.Tick
    Dim time As Long = Label22.Text
    If percentageTotal = 0 Then
        SetLabelText_ThreadSafe(Me.lblEstTimeLeft, "Estimated Time Left (All Files): Estimating...")
    Else
         Dim secondsRemaining As Double = (Overallsize - filetotalsofarcopied) / (filetotalsofarcopied - byteslastsecond)
        Dim ts As TimeSpan = TimeSpan.FromSeconds(secondsRemaining)

Can anyone correct my logic for the time remaining to be more realistic?

Upvotes: 0

Views: 719

Answers (1)

Visual Vincent
Visual Vincent

Reputation: 18320

The problem with your code is that you increment filetotalsofarcopied by the entire file size even though the entire file isn't copied yet. You should increment it as you copy a block of data.

So remove this:

'Calculate data being moved for eta to completion
Dim filetotalbytes As Double = ChildFile.Length
filetotalsofarcopied = filetotalbytes + filetotalsofarcopied

and put it in your While-loop instead:

BytesRead = CopyStream.Read(Buffer, 0, Buffer.Length)
NewStream.Write(Buffer, 0, BytesRead)

filetotalsofarcopied += BytesRead

percentageTotal = ((NewStream.Length + filetotalsofarcopied) / Overallsize * 100)
percentageTotal = Decimal.Round(percentageTotal)

This should make both the time estimation work correctly, and the percentage display.


You should also remove this:

'Do the copy
ChildFile.CopyTo(Path.Combine(DestDir.FullName, ChildFile.Name), True)

because you're wasting both time and resources by copying the file twice.


EDIT:

Actually, I made a mistake by missing something.

This:

percentageTotal = ((NewStream.Length + filetotalsofarcopied) / Overallsize * 100)

should be this:

percentageTotal = (filetotalsofarcopied / Overallsize * 100)

since the current amount of written bytes are already added to filetotalsofarcopied via the BytesRead variable.

Upvotes: 1

Related Questions