locked
how to use progress bar to vb.net form for copy a file

    Question

  • Hi guies!

    I am using  this type of code

    My.Computer.FileSystem.CopyFile(strSource, strDestination, FileIO.UIOption.AllDialogs)

    but i want to like  this...

                ProgressBar1.Value = 0
                Cursor.Current = Cursors.WaitCursor
                Timer1.Start()
                File.Copy(TextBox1.Text, TextBox2.Text, True)
                Label1.Text = "file copied."

       progressBar1.Value=100      

        Cursor.Current = Cursors.Default
    .            File.Delete(TextBox3.Text)

    ....................

    how to increase progress bar according to size transfer of a file. and progress Bar Value should  increase according to file size transfer.

    Because i am not getting how much size transfer of a file........???

    Please give me some code ..........

    regards!

    Balram Sharma

    Thursday, October 04, 2012 9:29 AM

Answers

  • Try this:  Start a new Windows Forms application and replace the code on Form1 with

    Imports System.Net
    Imports System.IO
    Public Class Form1
      Protected Overrides Sub OnLoad(e As EventArgs)
        MyBase.OnLoad(e)
        CopyBtn.Text = "Copy File"
        CopyBtn.Parent = Me
        ProgBar.Left = CopyBtn.Right
      End Sub
      Dim WithEvents CopyBtn As New Button
      Dim ProgBar As New ProgressBar
      Dim WithEvents FileCopier As New WebClient
      Private Sub CopyBtn_Click(sender As Object, e As EventArgs) Handles CopyBtn.Click
        Dim OFD As New OpenFileDialog
        OFD.Title = "Select file to copy"
        If Not OFD.ShowDialog() = DialogResult.OK Then Return
        Dim FBD As New FolderBrowserDialog
        FBD.Description = "Select destination folder"
        If Not FBD.ShowDialog = DialogResult.OK Then Return
        CopyBtn.Enabled = False
        ProgBar.Parent = Me
        FileCopier.DownloadFileAsync(New Uri(OFD.FileName), Path.Combine(FBD.SelectedPath, OFD.SafeFileName))
      End Sub
      Private Sub FileCopier_DownloadProgressChanged(sender As Object, e As DownloadProgressChangedEventArgs) Handles FileCopier.DownloadProgressChanged
        ProgBar.Value = e.ProgressPercentage
      End Sub
      Private Sub FileCopier_DownloadFileCompleted(sender As Object, e As System.ComponentModel.AsyncCompletedEventArgs) Handles FileCopier.DownloadFileCompleted
        ProgBar.Parent = Nothing
        CopyBtn.Enabled = True
      End Sub
    End Class
    

    Thursday, October 04, 2012 6:30 PM

All replies

  • Do not use the Copy commands built into Visual Basic or VB.NET.  Write your own Copy command that opens the source file as a FileStream, which has a Length property that tells you the file length in bytes.  You could use the types BinaryReader to read the bytes to a MemoryStream, and BinaryWriter to write the bytes to a new file location/name. 

    Get that part working first, then worry about adding the ProgressBar.  Use a For/Next loop to read, zero to Length.  Do the same for writing the  file back to disk, use a For/Next loop.  The loop will make it easier to to ReportProgress to the ProgressBar. 

    Once that works as it should, I would use a Timer to update the Progressbar ever 100 milliseconds, not for every byte that you read or write.  Perhaps someone feels inspired enough to write it for you.

    Hope this helps.

    Rudy   =8^D


    Mark the best replies as answers. "Fooling computers since 1971."

    http://thesharpercoder.blogspot.com/

    Thursday, October 04, 2012 3:43 PM
  • This is probably not the best way of doing this, but you're going to want something like this:

    Option Strict On
    Imports System.IO
    Public Class Form1
        Public Sub CopyFile(SourcePath As String, DestPath As String, ProgressBar As ProgressBar)
            Try
                Dim FileBytes As Byte() = My.Computer.FileSystem.ReadAllBytes(SourcePath)
                ProgressBar.Minimum = 0
                ProgressBar.Maximum = 100
                Dim Percentage As Integer = 0
                For I = 0 To UBound(FileBytes)
                    Percentage = CInt((I / FileBytes.Count) * 100)
                    ProgressBar.Value = Percentage
                    ProgressBar.Refresh()
                    Label1.Text = Percentage.ToString
                    Application.DoEvents()
                    Dim B(0) As Byte
                    B = {FileBytes(I)}
                    My.Computer.FileSystem.WriteAllBytes(DestPath, B, True)
                Next
            Catch ex As Exception
                MsgBox(ex.Message)
            End Try
        End Sub
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim SourceOFD As New OpenFileDialog
            SourceOFD.Title = "Select Source File"
            If SourceOFD.ShowDialog = Windows.Forms.DialogResult.OK Then
                CopyFile(SourceOFD.FileName, My.Computer.FileSystem.SpecialDirectories.Desktop & "\" & "test" & SourceOFD.SafeFileName, ProgressBar1)
            End If
        End Sub
    End Class


    If you want something you've never had, you need to do something you've never done.

    Thursday, October 04, 2012 4:30 PM
  • No, that is not a good way of doing that.  How many times per second would you estimate that you are updating the ProgressBar?  There is no need to update the control more than 20-30 times per second, which why I suggested using a timer to update the control.  The WinForms Timer control is not accurate for interval settings less than roughly 50 milliseconds.

    http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx  Refer to "Note" section

    Without running it, I would expect your code to "hang" and a call to Application.DoEvents "fixes" it.  The problem is that your code updates the control so fast that it cannot repaint before you update it again, which forces another redraw.  Calling DoEvents simply forces the OS to begin a new repaint without waiting for the control to be completely redrawn from the previous update. 

    Rudy  =8^D


    Mark the best replies as answers. "Fooling computers since 1971."

    http://thesharpercoder.blogspot.com/

    Thursday, October 04, 2012 5:14 PM
  • No, that is not a good way of doing that.  How many times per second would you estimate that you are updating the ProgressBar?  There is no need to update the control more than 20-30 times per second, which why I suggested using a timer to update the control.  The WinForms Timer control is not accurate for interval settings less than roughly 50 milliseconds.

    http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx  Refer to "Note" section

    Without running it, I would expect your code to "hang" and a call to Application.DoEvents "fixes" it.  The problem is that your code updates the control so fast that it cannot repaint before you update it again, which forces another redraw.  Calling DoEvents simply forces the OS to begin a new repaint without waiting for the control to be completely redrawn from the previous update. 

    Rudy  =8^D


    Mark the best replies as answers. "Fooling computers since 1971."

    http://thesharpercoder.blogspot.com/

    I am not sure I understand you, can you show a better way? ;]

    If you want something you've never had, you need to do something you've never done.

    Thursday, October 04, 2012 5:29 PM
  • Here, this one updates the progressbar every kilobyte you copy, instead of every byte.

    Option Strict On
    Public Class Form1
        Public Sub CopyFile(SourcePath As String, DestPath As String, ProgressBar As ProgressBar)
            If My.Computer.FileSystem.FileExists(DestPath) Then
                My.Computer.FileSystem.DeleteFile(DestPath)
            End If
            Dim FileBytes As Byte() = My.Computer.FileSystem.ReadAllBytes(SourcePath)
            ProgressBar.Minimum = 0
            ProgressBar.Maximum = 100
            Dim Percentage As Integer = 0
            For I = 0 To UBound(FileBytes)
                If I Mod 1024 = 0 Then
                    Percentage = CInt((I / FileBytes.Count) * 100)
                    ProgressBar.Value = Percentage
                    ProgressBar.Refresh()
                    Application.DoEvents()
                End If
                Dim B(0) As Byte
                B = {FileBytes(I)}
                My.Computer.FileSystem.WriteAllBytes(DestPath, B, True)
            Next
            ProgressBar.Value = 100
        End Sub
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim SourceOFD As New OpenFileDialog
            SourceOFD.Title = "Select Source File"
            If SourceOFD.ShowDialog = Windows.Forms.DialogResult.OK Then
                CopyFile(SourceOFD.FileName, My.Computer.FileSystem.SpecialDirectories.Desktop & "\" & "test" & SourceOFD.SafeFileName, ProgressBar1)
            End If
        End Sub
    End Class


    If you want something you've never had, you need to do something you've never done.



    Thursday, October 04, 2012 5:39 PM
  • How fast are the updates to the PB being performed?  Use System.Diagnostics.Stopwatch class to find out.  If it cannot work without a call to DoEvents, then you are probably updating the control much too quickly....which is a waste of CPU time.

    Rudy   =8^D


    Mark the best replies as answers. "Fooling computers since 1971."

    http://thesharpercoder.blogspot.com/

    Thursday, October 04, 2012 6:06 PM
  • Try this:  Start a new Windows Forms application and replace the code on Form1 with

    Imports System.Net
    Imports System.IO
    Public Class Form1
      Protected Overrides Sub OnLoad(e As EventArgs)
        MyBase.OnLoad(e)
        CopyBtn.Text = "Copy File"
        CopyBtn.Parent = Me
        ProgBar.Left = CopyBtn.Right
      End Sub
      Dim WithEvents CopyBtn As New Button
      Dim ProgBar As New ProgressBar
      Dim WithEvents FileCopier As New WebClient
      Private Sub CopyBtn_Click(sender As Object, e As EventArgs) Handles CopyBtn.Click
        Dim OFD As New OpenFileDialog
        OFD.Title = "Select file to copy"
        If Not OFD.ShowDialog() = DialogResult.OK Then Return
        Dim FBD As New FolderBrowserDialog
        FBD.Description = "Select destination folder"
        If Not FBD.ShowDialog = DialogResult.OK Then Return
        CopyBtn.Enabled = False
        ProgBar.Parent = Me
        FileCopier.DownloadFileAsync(New Uri(OFD.FileName), Path.Combine(FBD.SelectedPath, OFD.SafeFileName))
      End Sub
      Private Sub FileCopier_DownloadProgressChanged(sender As Object, e As DownloadProgressChangedEventArgs) Handles FileCopier.DownloadProgressChanged
        ProgBar.Value = e.ProgressPercentage
      End Sub
      Private Sub FileCopier_DownloadFileCompleted(sender As Object, e As System.ComponentModel.AsyncCompletedEventArgs) Handles FileCopier.DownloadFileCompleted
        ProgBar.Parent = Nothing
        CopyBtn.Enabled = True
      End Sub
    End Class
    

    Thursday, October 04, 2012 6:30 PM
  • Another option is to pinvoke CopyFileEx which provides for a callback function to report progress.  See this:  http://www.pinvoke.net/default.aspx/kernel32/CopyFileEx.html
    Thursday, October 04, 2012 9:04 PM
  • thanks your Suggestion!

    ..... if i use like this!

     Dim SourcePath As String = TextBox1.Text
            Dim DestinationPath As String = TextBox2.Text

            Dim sr As New IO.FileStream(SourcePath, IO.FileMode.Open) 'source file
            Dim sw As New IO.FileStream(DestinationPath, IO.FileMode.Create) 'target file, defaults overwrite
            Dim len As Long = sr.Length - 1
            For i As Long = 0 To len
                sw.WriteByte(sr.ReadByte)
                If i Mod 1000 = 0 Then 'only update UI every 1 Kb copied
                    ProgressBar1.Value = i * 100 / len
                    Application.DoEvents()
                End If
            Next
            sr.Close()
            sw.Close()

    but i use stream read/write that will take so much extra time for  big size file than compare to copy command.

    i want to use copy command with progress bar Because
     and it take minimum time compare to stream read/write file

    Regard!

    Balram Sharma


    Friday, October 05, 2012 7:38 AM
  • Thanks paul Ishak ,

    If i will use ...

       My.Computer.FileSystem.WriteAllBytes(DestPath, B, True)

    that will take so much time  compare to copy command ........

    can u give me some suggestion about using progress bar with copy command 

    Regards!

    Balram sharma

    Friday, October 05, 2012 7:44 AM
  • Balram, you are quite wrong in your estimate of performance of a program which does 4KB read-writes with a progress bar tickled by a timer vs. MS Copy

    I just put together a VB 2010 example and copied an 8GB file using the VB program and then MS Copy.  The time was exactly the same for both: 94 seconds on my feeble hardware.

    IO is a bottleneck when compared with CPU performance, so even an ineficient program should copy disk as fast as the hardware will allow.

    If you're interested in the sample program to which I'm referring, it's located here https://app.dumptruck.goldenfrog.com/p/uscp495_g0


    • Edited by clover1939 Friday, October 05, 2012 8:48 PM unthreaded
    Friday, October 05, 2012 8:19 PM
  • JohnWein, this is BRILLIANT!!!  Thanks for the education.  So little time:-(

    • Edited by clover1939 Friday, October 05, 2012 8:47 PM attribution
    Friday, October 05, 2012 8:28 PM
  • Balram, you are quite wrong in your estimate of performance of a program which does 4KB read-writes with a progress bar tickled by a timer vs. MS Copy

    I just put together a VB 2010 example and copied an 8GB file using the VB program and then MS Copy.  The time was exactly the same for both: 94 seconds on my feeble hardware.

    IO is a bottleneck when compared with CPU performance, so even an ineficient program should copy disk as fast as the hardware will allow.

    If you're interested in the sample program to which I'm referring, it's located here https://app.dumptruck.goldenfrog.com/p/uscp495_g0


    The OP might not be interested, but I am. Could you provide an easier way to download your project, such as a single file like a zip? ms skydrive is preferred...

    If you want something you've never had, you need to do something you've never done.

    Friday, October 05, 2012 9:12 PM
  • Sure Paul.  Sorry about SkyDrive, I already have an account with GigaNews (DumpTruck).  Let me know if the link is unusable and I'll try your suggestion.

    https://app.dumptruck.goldenfrog.com/p/6HXp5nX9vV

    Friday, October 05, 2012 9:42 PM
  • Sure Paul.  Sorry about SkyDrive, I already have an account with GigaNews (DumpTruck).  Let me know if the link is unusable and I'll try your suggestion.

    https://app.dumptruck.goldenfrog.com/p/6HXp5nX9vV

    3.27 GB, 62 seconds. Nice example! On my first go(when answering this) I went to use the binary writer, but for some reason I was stuck writing one bit at a time... Must have been a misinterpretation on my part.

    If you want something you've never had, you need to do something you've never done.

    Friday, October 05, 2012 10:00 PM
  • Thanks Paul, but the nicest example was JohnWein's; kudos to you and him for so much contribution.
    Friday, October 05, 2012 10:14 PM