For those that do not know what Recursion is, a recursive method is a method that calls upon itself.
In order to understand recursion, one must first understand recursion
In order to create your backup program, you will need on your windows form application:
- 2 TextBoxes - 1 called txtMainFolder and 1 called txtFolderBackup
- 1 Button - Name this btnBackup
- 1 Checkbox - Name this cbNoOverwrite
Spoiler for whole code:
First thing you need to is declare global variables that will be used and turn Option strict on:
Option Strict On Imports System.IO Dim FolderDirectory As New Hashtable Dim MainFolder As String Dim lstAllFiles As New List(Of String) Dim lstDirectories As New List(Of String) Dim CountMarker As Integer = 0
These should be self explanatory once you see the whole code. Next we will add the code for when the user has entered in the folder locations. txtMainFolder should be the folder location from where the program will copy all files and folders from and txtFolderBackup will be the location it will copy to. The program will copy the files and folders in the same layout as where it copied it from.
Private Sub btnBackup_Click(sender As Object, e As EventArgs) Handles btnBackup.Click 'Check textboxes aren't empty If txtFolderBackup.Text = "" OrElse txtMainFolder.Text = "" Then MessageBox.Show("Please fill in all boxes!", "User Error ") Else MainFolder = txtMainFolder.Text Dim count As Integer = 0 FolderDirectory.Add(count, txtFolderBackup.Text) lstAllFiles.AddRange(Directory.GetFiles(MainFolder)) 'copy files that are in the primary folder CopyFiles(count) 'Add directories lstDirectories.AddRange(Directory.GetDirectories(MainFolder)) 'start the loop to search through all the folders and back up them 'foldermarker is used to keep track of folder locations, especially useful as this uses recursion, as the foldermarker keeps track of folder layout Dim FolderMarker As Integer = 0 For Each folder In lstDirectories CopyDirectories(folder, count, FolderMarker) Next 'Clear all lists and count, so program is ok to run again lstAllFiles.Clear() lstDirectories.Clear() FolderDirectory.Clear() count = 0 CountMarker = 0 txtFolderBackup.Text = "" txtMainFolder.Text = "" cbNoOverwrite.Checked = False MessageBox.Show("All files are backed up!", "Completed") End If End Sub
Once this button has been clicked, it will first assign variables to its corresponding lists and check to make sure all text boxes are filled in. The program will first copy the files that are in the main folder by calling the sub procedure CopyFiles. The program will then read in all the directories in the folder and start reading sub procedure CopyDirectories, which is the sub taht will use recursion to call upon itself. After its done this it will clear all lists files etc and show a message that it's completed.
The sub procedure CopyFiles:
''' <summary> ''' This is a method that copies files in the chosen directory into the backup location ''' </summary> ''' <param name="count">This parameter is used to pick the correct folder directory when copying files over</param> ''' <remarks></remarks> Sub CopyFiles(ByVal count As Integer) Try 'For each file in folder grab information about that file. For Each File In lstAllFiles Dim FileInfo As New FileInfo(File) Dim Filename As String = FileInfo.Name Dim FileLocation As String = FileInfo.FullName Dim FileDate As Date = FileInfo.LastWriteTime 'If the backup folder contains the file already, compare dates on file and if newer overwrite If System.IO.File.Exists(Path.Combine(CStr(FolderDirectory(count)), Filename)) Then Dim TempFileinfo As New FileInfo(Path.Combine(CStr(FolderDirectory(count)), Filename)) Dim TempFileDate As Date = TempFileinfo.LastWriteTime Dim result As Integer = DateTime.Compare(FileDate, TempFileDate) 'if result is less than 0 then the file is earlier than the backed up file, if result equals 0 then they are the same, 'if result is more than 0 then the file newer than the backuped file, so file needs to be copied over if newer 'Only overwrite file over if checkbox is not ticked, this way only files that are not previously there will get copied across If result > 0 AndAlso cbNoOverwrite.Checked = False Then System.IO.File.Copy(FileLocation, Path.Combine(CStr(FolderDirectory(count)), Filename), True) End If Else 'file does not already exist so copy over System.IO.File.Copy(FileLocation, Path.Combine(CStr(FolderDirectory(count)), Filename)) End If Next Catch ex As Exception MessageBox.Show("Something went wrong. " & ex.ToString, "Data error ") End Try End Sub
This sub procedure is called upon every time the program reaches a new folder and will copy all files in that folder over to the new one. If the check box cbNoOverwrite is ticked then it will not overwrite the existing files.
The sub procedure CopyDirectories:
''' <summary> ''' This sub copies folder directories over to the backup location and uses recursion to call itself so that it looks at directories in itself and also calls CopyFiles to copy the files over in those directories ''' </summary> ''' <param name="Folder">This parameter holds the folder location</param> ''' <param name="count">This parameter holds the count used to add more directories into the hashtable and used so that it creates a unique ID for each folder</param> ''' <param name="FolderMarker">this parameter is used a marker so that it adds the correct folder directory path</param> ''' <remarks></remarks> Sub CopyDirectories(ByVal Folder As String, ByVal count As Integer, ByVal FolderMarker As Integer) Try 'Check if folder exists in backup and if it doesnt copy entire folder over 'if folder exists then go through each folder and copy files/folders over 'use recursion to call Dim FolderInfo As New DirectoryInfo(Folder) Dim Folderlocation As String = FolderInfo.FullName Dim FolderName As String = FolderInfo.Name Dim lstTempFolderDirectories As New List(Of String) lstTempFolderDirectories.AddRange(Directory.GetDirectories(Folderlocation)) 'if the folder does not exist then copy folder and contents over otherwise read through contents and update if necassary If Directory.Exists(Path.Combine(CStr(FolderDirectory(count)), FolderName)) Then lstAllFiles.Clear() lstAllFiles.AddRange(Directory.GetFiles(Folderlocation)) 'Loop until the count is higher than the countmarker so that the count is a new number and that the FolderDirectory doesnt try to add a directory in a used key Do Until count > CountMarker count += 1 Loop CountMarker = count 'Add directory to hashtable FolderDirectory.Add((count), (Path.Combine(CStr(FolderDirectory(FolderMarker)), FolderName))) 'Add 1 to the foldermarker here FolderMarker += 1 'Copy files in this directory over CopyFiles(count) If lstTempFolderDirectories.Contains(Nothing) Then Else 'Use recursion to call this same subroutine so that it can go through each subfolders For Each Folder In lstTempFolderDirectories CopyDirectories(Folder, count, FolderMarker) Next End If Else 'if folder does not exist then copy over whole of the directory including everything inside it My.Computer.FileSystem.CopyDirectory(Folderlocation, Path.Combine(CStr(FolderDirectory(FolderMarker)), FolderName)) End If Catch ex As Exception MessageBox.Show("Something went wrong. " & ex.ToString, "Data error ") End Try End Sub
The sub procedure CopyDirectories uses recursion to call upon itself to read through each folder and copy them and call upon CopyFiles to copy the files over. Recursion is extremely helpful in this case because when backing folders up, each folder it gets to can have more folders inside them to back up and so on. So once it does finished with one folder it will go back and can continue with next folder and read through that folder. It does this by the use of a Hash Table and giving each directory a unique number by use of the FolderMarker. Tho if the folder doesnt exist in the backip location then it will simply copy the folder over and all its contents.
I have commented throughout my code on what it does. So hopefully this has helped people. There are more ways of improving on this, for example adding a message box to ask the user do they want to overwrite an existing file rather than just having a check box.