Introduction

I have been working with the .NET framework for several weeks now and I really enjoy the API. But sometimes I miss some features I need right now, even if I expect the framework to grow and get new classes and capabilities in the forthcoming versions (like Java did).

This article doesn't try to teach something but just gives a solution to anyone who needs it. I tried to keep it simple with few lines of code.

The FileSystem class

This class includes high level functions missing in the standard System.IO namespace. The class provided here only includes a directory to directory copy function for the moment, and the purpose of this article is to fix this .NET missing feature that many VB developers (for example) are used to.

The function takes two absolute paths (source directory and destination directory) as parameters and returns a boolean equal to truewhen the copy succeeds. Please note that this function automatically overwrites a destination file with the same name. Of course all subdirectories are also copied recursively.

An usage example

// After a successful copy, you can then call
// Directory.Delete(@"c:\MySrcDirectory") to mimic a Directory.Move behaviour
try{
copyDirectory(@"c:\MySrcDirectory",@"c:\MyDstDirectory");
}
catch(Exception Ex){
Console.Error.WriteLine(Ex.Message);
}

Conclusion

This article is just a tip targeted to beginners or newcomers who noticed this missing feature in the .NET framework. It is provided as a possible solution, but I encourage anyone to write his own function.

Happy Coding !!!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

I modified it and post the modified part here:because I tried to use it in my project, but failed(Directory.GetFileSystemEntries(Src, SrcFilterPattern[i]) got nothing at all.)public static void CopyDirectory(string Src,string Dst, string[] SrcFilterPattern){

First of all its a great article and it saved me tons of time.
My task was to back up a huge folder on backup server. On production server I have a backup server's mapped drive as "s". Now everytime I try to backup the directory, I get an error message "Could not find a part of the path "s:\".

Public Sub CopyDir(ByVal Src As String, ByVal Dst As String)
Dim Files() As String, Element As String
If Microsoft.VisualBasic.Right(Dst, Dst.Length - 1) <> Path.DirectorySeparatorChar Then
Dst &= Path.DirectorySeparatorChar
End If
If Not Directory.Exists(Dst) Then Directory.CreateDirectory(Dst)
Files = Directory.GetFileSystemEntries(Src)
For Each Element In Files
If Directory.Exists(Element) Then
CopyDir(Element, Dst & Path.GetFileName(Element))
Else
File.Copy(Element, Dst & Path.GetFileName(Element), True)
End If
Next Element
End Sub

You can change the line: If Microsoft.VisualBasic.Right(Dst, Dst.Length - 1) <> Path.DirectorySeparatorChar Thento: If Not dst.EndsWith(Path.DirectorySeparatorChar) Then

Even better is the fact that, the whole if ... end if statement is not need with the following revisions:
If Directory.Exists(Element) Then
CopyDir(Element, Dst & Path.GetFileName(Element))
Else
File.Copy(Element, Dst & Path.GetFileName(Element), True)
End If

is Changed to:
If Directory.Exists(Element) Then
CopyDir(Element, Path.Combine(Dst, Path.GetFileName(Element)))
Else
File.Copy(Element, Path.Combine(Dst, Path.GetFileName(Element)), True)
End If

The Path.Combine method will concatinate the Path.DirectorySeparatorChar onto the first argument if it is not already there!

So here is a slightly tweeked version of the whole thing:
Function CopyDir(ByVal SrcPath As String, ByVal DestPath As String)

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

Dim files() As String

files = Directory.GetFileSystemEntries(SrcPath)
For Each element As String In files
'Sub directories
If Directory.Exists(element) Then
CopyDir(element, Path.Combine(DestPath, Path.GetFileName(element)))
Else 'Files
File.Copy(element, Path.Combine(DestPath, Path.GetFileName(element)), True)
End If
Next
End Function

Great question because I saw someone showing this solution in a newsgroup .

What about using a shell function to copy the directory ?Advantages:
- Maybe the copy will be faster because you use pure native code.Problems:
- Your code is not 100% .NET compliant.
- Your code is not portable to another framework version (like mono on Linux) because you rely on Windows commands.
- No exceptions will be raised in case of an error occurring during the shell copy.
- You start a new external process.

GriffonRL wrote:Great question because I saw someone showing this solution in a newsgroup .

Hehe. Believe me this is my own question. I did not see it in a newsgroup
I have been using my approach for years and never had a problem yet.

GriffonRL wrote:- Your code is not 100% .NET compliant.
- Your code is not portable to another framework version (like mono on Linux) because you rely on Windows commands.

Yeah you are right. I never thought that because framework compatibility or OS independency is never an issue for me. I do not care about that :P

GriffonRL wrote:- No exceptions will be raised in case of an error occurring during the shell copy.

Yes but you will get a return value which indicates if the operation is sucessfull or not. Isn't it good enough? Hmmm. Well in fact not. I admit that C# is a very very nice language and the one who uses C# should use it in C# way, not the old C way. So let me answer my question: NO. Using Exceptions is better.
Hey, but you can check the value and raise your own exception

GriffonRL wrote:- You start a new external process.

I really didn't know that. Are you sure about that?

PS: One nice thing with using Shell functions is that you can put the files directly to the Recycle Bin (instead of deleting them).

Lastly, let me ask you another question: How is your experience with .NET till now? Is it really more productive than VC++? I love C#; but I do not like the .NET Framework it self and I hate the CLR (or whatever it is, the intermediate compiler thing - the code is not compiled into the native code).
I hope someday, Microsoft will come up with a native C# compiler with a new version of MFC (I dont want any language interoperability. All I want is to use a language like C# not C++ ).

Yes I agree that C# is a very nice language and we will soon get new important features like generics .
I have a long experience with Java and C++, and I found C# very easy to learn with that background.
I first played a little bit with ASP.NET 1 year ago but stopped for several months. I resumed my experiments a few months ago with the Visual Studio .NET release, and now we use .NET to build our business applications.
I really think this language is more productive than C++, or at least less harmful than C++. Writing bad C++ code is easier than writing bad C# code. Of course C# still miss some features but is is coming soon.
I have nothing against the .NET framework and it is full of helpful classes that speed up the development process a lot. I programmed a lot with Java and really enjoyed the Java APIs. The new .NET framework makes more sense than the system DLL we used to for Windows programming. MFC for example has a heavy heritage behind it.
The beauty of .NET if you develop only for Windows platforms, is that you can still write critical functions in a native C++ DLL and call them from your skeleton program written in C#/.NET.
Because the C# language has been submitted to the ECMA and specifications are available, anybody could write a C# compiler to native code. Or maybe someone will create a program to convert all CLR code into native code: some solutions exist for Java where .class files are converted into Windows .EXE.

First off, it's a great article that points out another thing that's wrong with the FCL. Now...if you don't mind, I'd like to critique it a bit.

First off, there's no reason to return bool. A better way to do it would be to use straight Exceptions. To put it in Rama's words: "It's not the way of the Framework." The System.IO.File.Copy() method is marked as public static void Copy(), so what you should do is make this return void and stick to using Exceptions.

That's wrong. Your code, as part of a class library, should never visually display information...and that includes writing to the console. You should let the consumer handle that. Jeffrey Richter points this out in his book Applied Microsoft .NET Framework Programming, the DataGrid displays a MessageBox when there is an error in setting the CurrentCell property. I know that as an app-writer, I would hate to have a component or utility that I was using display visual information to the user without my consent.

Oh, and you don't need a constructor in your class unless there are other methods that are not marked as static. So I would remove that because really, this class should never be instantiated.

That being said, it's a great implementation for something that should be in the Framework.

Thank you for your nice post !
I totally agree with all your remarks .
I have to explain why I have this Console.Error.WriteLine(Ex.Message) stuff and a boolean just after.
That's because I catch the exceptions in the static function, the calling method never gets the info. So that's why I return a boolean.
But why I am catching the exception in the function ? Just because this function is coming from my framework and it is the way I wanted it. Actually, I redirect all Console.Error.WriteLine to a XML error file (see http://www.codeproject.com/csharp/XML_Error_Log.asp[^]) and it is important the message comes from the function. But you can tell me I can retrow the exception just after I logged it and you are right: it will be the best solution to be "in the way of the framework".
I think I will update the article, reduce the code size again and try/catch the exceptions in the usage example.
And yes, I can remove this nasty useless constructor even if it doesn't create any trouble . I use a template to build all my classes and I always have one.

GriffonRL wrote:That's because I catch the exceptions in the static function, the calling method never gets the info. So that's why I return a boolean.

You can still throw an Exception back up the call stack. All that you have to do is:

try
{//Insert code here}
catch(Exception ex)
{throw ex;}

That'll throw the Exception back up the call stack to the caller of the function.

In fact...*Brilliant thought comes to David*

Why don't you do some extra work in the catch block...before you throw the exception back up the stack. One thing that I hate is when Windows starts copying a directory and then one file can't be moved, so I have a partial directory...So why don't you delete the destination files and folder if an error happened. That way it's all or nothing. I know a lot of other people who hate this too...so you may want to look into implementing that.

Wow, that would be really hard, because he has to keep the track of all copied files. And since he is using a recursive algorithm with static functions this may be really hard. Also, he should not delete the files that he has overwritten. Because of that, while keeping track of the files, he should also check if that file already exists or not. This list may become longer and doing all of these stuff is much harder than this simple and fast function

Yes I agree about throwing the exception back after catching it. It is what I called "retrow" when I responded to your first post.
Sorry for the typo ...

Your second remark about partial copies is interesting, but I would like to keep this version simple. And what if you replace an existing file during the copy ? If you roolback the process how do you retrieve the original without keeping a version somewhere ? Implementing this rollback procedure sounds a little bit overkill to me.

GriffonRL wrote:Your second remark about partial copies is interesting

Yeah...I wasn't thinking about this being a "simple" procedure. It would be quite hard to do what I was suggesting. I don't think that it would be very easy to do the rollback of the partial copy. And you are right. You would have to keep a temp version of the originals...