.comment-link {margin-left:.6em;}

kHSw

Wednesday, March 08, 2006

Copy a complete directory with progress bar

Some months ago I published an article explaining how to copy a file with a progressbar in VB.NET. I would like to thank you all for the great feedback on that article! Some days ago I received a mail with the question how to copy a whole directorystructure while showing the progress. So here's a possible solution. Please have a look at the original article first (http://khsw.blogspot.com/2005/08/copy-file-with-progressbar-in-vbnet.html).

The necessary API functions:
Private Delegate Function CopyProgressRoutine(ByVal totalFileSize As Int64, ByVal totalBytesTransferred As Int64, ByVal streamSize As Int64, ByVal streamBytesTransferred As Int64, ByVal dwStreamNumber As Int32, ByVal dwCallbackReason As Int32, ByVal hSourceFile As Int32, ByVal hDestinationFile As Int32, ByVal lpData As Int32) As Int32

Private Declare Auto Function CopyFileEx Lib "kernel32.dll" (ByVal lpExistingFileName As String, ByVal lpNewFileName As String, ByVal lpProgressRoutine As CopyProgressRoutine, ByVal lpData As Int32, ByVal lpBool As Int32, ByVal dwCopyFlags As Int32) As Int32


Here we declare some private variables. _totalFileSize will hold the total size of all files, _totalBytesCopied will contain the number of bytes that has been copied in the complete process.
Private _totalFileSize As Long = 0
Private _totalBytesCopied As Long = 0
Private _copyProgressRoutine As CopyProgressRoutine
Private Const ROOTFOLDER As String = "C:\Program Files\Common Files"
Private Const DESTFOLDER As String = "C:\Temp2"

The Click event of the button has been changed. First it will count the total size of all files in the rootfolder and its subfolders. After that, the recursive function CopyFiles will be called.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
GetTotalFileSize(New System.IO.DirectoryInfo(ROOTFOLDER))
_copyProgressRoutine = New CopyProgressRoutine(AddressOf CopyProgress)
CopyFiles(New System.IO.DirectoryInfo(ROOTFOLDER), DESTFOLDER)
End Sub

The CopyProgress function has been changed. The totalBytesTransferred of the current file will be added to the total amount of bytes already copied. The value of the progressbar will be calculated by adding the copied bytes of the current file to the number of bytes transferred by copying the previous files. This sum will be divided by the number of bytes that has to copied in total.
Private Function CopyProgress(ByVal totalFileSize As Int64, ByVal totalBytesTransferred As Int64, ByVal streamSize As Int64, ByVal streamBytesTransferred As Int64, ByVal dwStreamNumber As Int32, ByVal dwCallbackReason As Int32, ByVal hSourceFile As Int32, ByVal hDestinationFile As Int32, ByVal lpData As Int32) As Int32
ProgressBar1.Value = Convert.ToInt32((_totalBytesCopied + totalBytesTransferred) / _totalFileSize * 100)
Application.DoEvents()
End Function

The recursive function GetTotalFileSize will calculate the size of all files within the given folder and it's subfolders.
Private Sub GetTotalFileSize(ByVal folder As System.IO.DirectoryInfo)
For Each fi As System.IO.FileInfo In folder.GetFiles
_totalFileSize += fi.Length
Next
For Each di As System.IO.DirectoryInfo In folder.GetDirectories
GetTotalFileSize(di)
Next
End Sub

The recursive function CopyFiles will copy all files of the given folder and it's subfolders to a new destination. It the destionation (sub)folder does not exists, it will be created. After calling the CopyFileEx function the file size of the copied file will be added to _totalFileSize.
Private Sub CopyFiles(ByVal folder As System.IO.DirectoryInfo, ByVal destinationFolder As String)
If Not System.IO.Directory.Exists(destinationFolder) Then
System.IO.Directory.CreateDirectory(destinationFolder)
End If
For Each fi As System.IO.FileInfo In folder.GetFiles
CopyFileEx(fi.FullName, destinationFolder & "\" & fi.Name, _copyProgressRoutine, 0, 0, 0)
_totalBytesCopied += fi.Length
Next
For Each di As System.IO.DirectoryInfo In folder.GetDirectories
CopyFiles(di, di.FullName.Replace(ROOTFOLDER, DESTFOLDER))
Next
End Sub

15 Comments:

  • Excellent code.

    - Sachin

    By Anonymous Anonymous, at 7:52 AM  

  • If you want to be able to cancel the copy, you need to do the following:
    1) Change the declaration making the next to last param ByRef.
    2) Create a cancel variable and pass that variable when invoking the CopyFileEx method.
    3) Add a line within the For/Next loop of CopyFiles: If CType(bCancel, Boolean) Then Exit For
    4) When you want to cancel, set the variable to True: bCancel = CType(True, Int32)

    By Anonymous Anonymous, at 10:10 PM  

  • GENIUS! This is the code I've been looking for all day - works a treat! THANKS a lot. Rich.

    By Anonymous Anonymous, at 3:49 PM  

  • I really appreciate your comment!

    By Blogger kHSw, at 10:54 PM  

  • Have a problem with this, trying to copy everything of my usb stick. using the source as F:\ and destination as c:\temp2.

    It will only copy the files, not the folder. Also how would i go about putting a tad more info on here, like a timer?

    Many thanks for the great code!
    nathan

    By Anonymous Anonymous, at 12:46 AM  

  • Did you already manage copying from your USB stick?

    By Blogger kHSw, at 12:06 PM  

  • Really nice code. I search for this a long time.

    It works great.

    By Anonymous Anonymous, at 2:11 PM  

  • Just what i was looking for. It's not often you find code like this that works so easily the first time. Very clear presentation. Great job!

    By Anonymous Anonymous, at 7:44 PM  

  • Excellent code. Can i show the progress bars for each file that is copied?(each progress bar shows its own Percentage of completion).

    By Anonymous Anonymous, at 12:48 PM  

  • Excellent code.
    How to modify the above code for showing progress bar for each file( I have an array of files to be copied...and iam looping them one by one)
    And each progress bar will obviously show each file progress.

    By Anonymous Anonymous, at 12:51 PM  

  • Nice code

    By Blogger wefocusoncare, at 12:04 PM  

  • Like this code. But I want to do multiple copy to different destination folders and how can i use the same code in a backgroundworker? help would be really appreciated

    By Blogger Unknown, at 10:40 PM  

  • Excelente ejercicio!!!, me fue de gran ayuda, muchas gracias

    By Blogger Diego Vera, at 3:25 PM  

  • is there a C# version of this somewhere?

    By Anonymous Anonymous, at 5:03 PM  

  • I would just like to thank you for your clear code. I am not sure if .Net has got something better but at least I can find and understand your example.

    By Anonymous Anonymous, at 10:44 AM  

Post a Comment

<< Home


 
Stefanie Worm is het liefste vrouwtje van de wereld.
Melina is de liefste schatsie van de wereld (Erik De Maeyer).