How to do simple recursion (XCopy in C# (and VB))


Yesterday, I saw the following question in the C# NNTP group
(microsoft.public.dotnet.languages.csharp):

I need to get a listing of all folders and subfolders paths using C# .net
2.0.
such as .folderAsubfolderBsubfolderC
            
.folderAsubfolderD
             .folderAsubfolderDsubfolderE
Any
ideas, examples?

Simple recursion problem. The writer wrote back and stated he want to copy
all files from a CD, using C#, into an equivalent directory structure on the
drive. Now, I might choose to solve this by making a P/Invoke call to the API
method that does xcopy or wrap XCopy in a Process object, but we can also solve
this through simple recursion. Here is the follow up:

Ok, so I’ve got a CD that has folders and files on that media.  I’m
creating
a small app that will basically copy from the Cd to the hard drive
and
maintain that same folder structure found on the CD.  I’m
thinking
the easiest way to such as task, is to create a string array with
the folder
paths on the CD, then create that folder structure on the hard
drive, then I
can copy from source to destination.

Now, suppose we create a simple class library with a single class to do this
move. I will leave the method as static, as it really does nothing more than
read the directory, move files and then check for subdirectories. The entire
class is represented below (this is a rough draft, of course):

using System.IO;

namespace GBWorld.RecursiveCopy.Business
{
    public class DirectoryCopier
    {
        public static void CopyDirectory(string originalDirectory, string newDirectory)
        {
            MoveDirectory(originalDirectory, newDirectory);
        }

        private static void MoveDirectory(string originalDirectory, string newDirectory)
        {
            //Ensure new directory exists
            if (!Directory.Exists(newDirectory))
                Directory.CreateDirectory(newDirectory);

            DirectoryInfo oldDir = new DirectoryInfo(originalDirectory);

            //Copy files
            foreach (FileInfo file in oldDir.GetFiles())
            {
                string oldPath = file.FullName;
                string newPath = newDirectory + "\" + file.Name;
                File.Copy(oldPath, newPath);
            }

            foreach(DirectoryInfo dir in oldDir.GetDirectories())
            {
                string oldPath = dir.FullName;
                string newPath = newDirectory + "\" + dir.Name;
                MoveDirectory(oldPath, newPath);
            }
        }
    }
}

The yellow highlighted part is where we are using recursion. The orange highlighted section helps this work, as it ensures the new directory is created. And the green highlighted section copies the files from the directory.

To call this, you can do something as simple as this console application:

using GBWorld.RecursiveCopy.Business;

namespace GBWorld.RecursiveCopy.UI.Console
{
    class Program
    {
        static void Main(string[] args)
        {
            string oldDir = "C:\temp\test1";
            string newDir = "C:\temp\test2";

            DirectoryCopier.CopyDirectory(oldDir, newDir);

            System.Console.WriteLine("Done");
            System.Console.Read();
        }
    }
}

Pretty Simple, eh? There is definitely more that can be done here for a production app. I should, for example, check if the original directory exists. I might also break down the new directory and make sure parent directories exists, as a call to create c:temptest2 will fail if c:temp does not exist. And we could add some instrumentation and logging to help when things fail. But, this is just a simple example.

BTW, this is a layered app. The UI is completely separate from the "business" code that holds the actual behavior. If you read this blog often, you will find I like to do this, as it makes it easy for me to change out user interfaces without rewriting application code. Here is how the projects look in the entire :application":

For those of you who are into VB, there is an easier way to copy directories using the My object. But, here is the recursion exercise in VB, with the same highlights (I copied this from Reflector rather than rewrite it):

Public Class DirectoryCopier

Public Shared Sub CopyDirectory(ByVal originalDirectory As String, ByVal newDirectory As String)
DirectoryCopier.MoveDirectory(originalDirectory, newDirectory)
End Sub

Private Shared Sub MoveDirectory(ByVal originalDirectory As String, ByVal newDirectory As String)

Dim oldPath As String
Dim newPath As String

If Not Directory.Exists(newDirectory) Then
Directory.CreateDirectory(newDirectory)
End If

Dim oldDir As New DirectoryInfo(originalDirectory)
Dim file As FileInfo

For Each file In oldDir.GetFiles
oldPath = file.FullName
newPath = (newDirectory & "" & file.Name)
File.Copy(oldPath, newPath)
Next

Dim dir As DirectoryInfo

For Each dir In oldDir.GetDirectories
oldPath = dir.FullName
newPath = (newDirectory & "" & dir.Name)
DirectoryCopier.MoveDirectory(oldPath, newPath)
Next

End Sub

End Class

Reflector is not as concise, so feel free to edit as needed to make it cleaner. I was not interested in writing VB code right this second, so Reflector made things easier for me.Wink

Peace and Grace,
Greg

Twitter: @gbworld

Leave a comment