|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionI was near the end of a drawn out development project for adding users to an Active Directory server when I was informed I would also need to set up their Thunderbird client settings. This required me to create a copy of a directory, sub-directories, and files over at the user's "My Documents" folder. I tried using Microsoft's MSDN Online to search for a way to copy directories with their subfolders and files, when I determined that the I then searched the internet for other user's code examples, hoping someone had found a solution to this seemingly simple problem. And I did come across a few; still, the code I did find was inelegant and very much a "quick fix". So I ended up writing my own. NEW! Version 3.0 DescriptionWritten October 18th, 2006 Well, after much more feedback and a lot of research, I give you Version 3 of the xDirectory Copier. This version is built on an almost completely different method: It's event-driven. Yes, that's right, the xDirectory object now copies files and subfolders on a separate thread, and responds with events. This version will work both with Console as well as GUI (such as Windows Forms-Based) programs. It is UI-Thread Friendly, so it will allow you to update your controls on the events. It can give you a progress report, and you can cancel the copy thread at any time. Also, you can set multiple file filters to copy multiple file types (see below). You'll definately want to download the provided code and look through it yourself. There's enough changes in the code that posting it here is probably just wasting your time. I will however post some highlights. So, to use this new class, you would do this: xDirectory Copier = new xDirectory();
Copier.ItemIndexed += new ItemIndexedEventHandler(Copier_ItemIndexed);
Copier.IndexComplete += new IndexCompleteEventHandler(Copier_IndexComplete);
Copier.ItemCopied += new ItemCopiedEventHandler(Copier_ItemCopied);
Copier.CopyComplete += new CopyCompleteEventHandler(Copier_CopyComplete);
Copier.CopyError += new CopyErrorEventHandler(Copier_CopyError);
Then, there are two ways to use the code once initialized. You can do as below: Copier.Source = new DirectoryInfo(sSource);
Copier.Destination = new DirectoryInfo(sDestination);
Copier.Overwrite = true;
Copier.FolderFilter = "*";
Copier.FileFilters.Add("*.jpg");
Copier.FileFilters.Add("*.bmp");
Copier.FileFilters.Add("*.png");
Copier.StartCopy();
Or, you can simply call the overloaded StartCopy Method: List<string> FileFilters = new List<string>();
FileFilters.Add("*.jpg");
Copier.StartCopy(sSource, sDestination, FileFilters, null, true);
If you place the Initialization part in a Form_Load method, and then put Usage part in a Button_Click event, it will run asynchronously and will allow you to update your controls (such as a progress bar) through the event methods. One of the best parts of this new class is that if there's an error in copying a file, instead of cancelling the entire process, it will simply send a 'CopyError' Event! So you can list the files that had errors in copying but continue to copy the rest of the files successfully! And here's the method that does all the work. It's a bit more complex-looking than version 2: /// <summary>
/// The Main Work Method of the xDirectory Class: Handled in a Separate Thread.
/// </summary>
/// <param name="StateInfo">Undefined</param>
private void DoWork(object StateInfo)
{
_CopierStatus = xDirectoryStatus.Started;
int iterator = 0;
List<DirectoryInfo> FolderSourceList = new List<DirectoryInfo>();
List<FileInfo> FileSourceList = new List<FileInfo>();
DirectoryInfo FolderPath;
FileInfo FilePath;
try
{
// Part 1: Indexing
///////////////////////////////////////////////////////
_CopierStatus = xDirectoryStatus.Indexing;
FolderSourceList.Add(_Source);
while (iterator < FolderSourceList.Count)
{
if (_CancelCopy) return;
foreach (DirectoryInfo di in
FolderSourceList[iterator].GetDirectories(_FolderFilter))
{
if (_CancelCopy) return;
FolderSourceList.Add(di);
OnItemIndexed(new ItemIndexedEventArgs(
di.FullName,
0,
FolderSourceList.Count,
true));
}
foreach (string FileFilter in _FileFilters)
{
foreach (FileInfo fi in
FolderSourceList[iterator].GetFiles(FileFilter))
{
if (_CancelCopy) return;
FileSourceList.Add(fi);
OnItemIndexed(new ItemIndexedEventArgs(
fi.FullName,
fi.Length,
FileSourceList.Count,
false));
}
}
iterator++;
}
OnIndexComplete(new IndexCompleteEventArgs(
FolderSourceList.Count,
FileSourceList.Count));
// Part 2: Destination Folder Creation
///////////////////////////////////////////////////////
_CopierStatus = xDirectoryStatus.CopyingFolders;
for (iterator = 0; iterator < FolderSourceList.Count; iterator++)
{
if (_CancelCopy) return;
if (FolderSourceList[iterator].Exists)
{
FolderPath = new DirectoryInfo(
_Destination.FullName +
Path.DirectorySeparatorChar +
FolderSourceList[iterator].FullName.Remove(0,
_Source.FullName.Length));
try
{
// Prevent IOException
if (!FolderPath.Exists) FolderPath.Create();
OnItemCopied(new ItemCopiedEventArgs(
FolderSourceList[iterator].FullName,
FolderPath.FullName,
0,
iterator,
FolderSourceList.Count,
true));
}
catch (Exception iError)
{
OnCopyError(new CopyErrorEventArgs(
FolderSourceList[iterator].FullName,
FolderPath.FullName,
iError));
}
}
}
// Part 3: Source to Destination File Copy
///////////////////////////////////////////////////////
_CopierStatus = xDirectoryStatus.CopyingFiles;
for (iterator = 0; iterator < FileSourceList.Count; iterator++)
{
if (_CancelCopy) return;
if (FileSourceList[iterator].Exists)
{
FilePath = new FileInfo(
_Destination.FullName +
Path.DirectorySeparatorChar +
FileSourceList[iterator].FullName.Remove(0,
_Source.FullName.Length + 1));
try
{
if (_Overwrite)
FileSourceList[iterator].CopyTo(FilePath.FullName,
true);
else
{
if (!FilePath.Exists)
FileSourceList[iterator].CopyTo(
FilePath.FullName, true);
}
OnItemCopied(new ItemCopiedEventArgs(
FileSourceList[iterator].FullName,
FilePath.FullName,
FileSourceList[iterator].Length,
iterator,
FileSourceList.Count,
false));
}
catch (Exception iError)
{
OnCopyError(new CopyErrorEventArgs(
FileSourceList[iterator].FullName,
FilePath.FullName,
iError));
}
}
}
}
catch
{ throw; }
finally
{
_CopierStatus = xDirectoryStatus.Stopped;
OnCopyComplete(new CopyCompleteEventArgs(_CancelCopy));
}
}
Old Version 2.0 DescriptionWritten May 18th, 2006 Updated July 25th, 2006 - Fixed a major (but minute) error, added a After so much feedback, I decided I would revisit the The original version was written in .NET 1.1, and since then, I've gotten used to .NET 2.0, so this is what the second version is written in. Everyone cheer for Generic Collections! Also, if you notice in the source code, the Some key points were brought up, both in my work and in the comments; hopefully, all these have been rectified to everyone's satisfaction!
Here's the /// <summary>
/// xDirectory.Copy() - Copy a Source Directory
/// and it's SubDirectories/Files
/// </summary>
/// <param name="diSource">The Source Directory</param>
/// <param name="diDestination">The Destination Directory</param>
/// <param name="FileFilter">The File Filter
/// (Standard Windows Filter Parameter, Wildcards: "*" and "?")</param>
/// <param name="DirectoryFilter">The Directory Filter
/// (Standard Windows Filter Parameter, Wildcards: "*" and "?")</param>
/// <param name="Overwrite">Whether or not to Overwrite
/// a Destination File if it Exists.</param>
/// <param name="FolderLimit">Iteration Limit - Total Number
/// of Folders/SubFolders to Copy</param>
public static void Copy(DirectoryInfo diSource,
DirectoryInfo diDestination,
string FileFilter, string DirectoryFilter,
bool Overwrite, int FolderLimit)
{
int iterator = 0;
List<DirectoryInfo> diSourceList =
new List<DirectoryInfo>();
List<FileInfo> fiSourceList =
new List<FileInfo>();
try
{
///// Error Checking /////
if (diSource == null)
throw new ArgumentException("Source Directory: NULL");
if (diDestination == null)
throw new ArgumentException("Destination Directory: NULL");
if (!diSource.Exists)
throw new IOException("Source Directory: Does Not Exist");
if (!(FolderLimit > 0))
throw new ArgumentException("Folder Limit: Less Than 1");
if (DirectoryFilter == null || DirectoryFilter == string.Empty)
DirectoryFilter = "*";
if (FileFilter == null || FileFilter == string.Empty)
FileFilter = "*";
///// Add Source Directory to List /////
diSourceList.Add(diSource);
///// First Section: Get Folder/File Listing /////
while (iterator < diSourceList.Count && iterator < FolderLimit)
{
foreach (DirectoryInfo di in
diSourceList[iterator].GetDirectories(DirectoryFilter))
diSourceList.Add(di);
foreach (FileInfo fi in
diSourceList[iterator].GetFiles(FileFilter))
fiSourceList.Add(fi);
iterator++;
}
///// Second Section: Create Folders from Listing /////
foreach (DirectoryInfo di in diSourceList)
{
if (di.Exists)
{
string sFolderPath = diDestination.FullName + @"\" +
di.FullName.Remove(0, diSource.FullName.Length);
///// Prevent Silly IOException /////
if (!Directory.Exists(sFolderPath))
Directory.CreateDirectory(sFolderPath);
}
}
///// Third Section: Copy Files from Listing /////
foreach (FileInfo fi in fiSourceList)
{
if (fi.Exists)
{
string sFilePath = diDestination.FullName + @"\" +
fi.FullName.Remove(0, diSource.FullName.Length);
//// Better Overwrite Test W/O IOException from CopyTo() ////
if (Overwrite)
fi.CopyTo(sFilePath, true);
else
{
///// Prevent Silly IOException /////
if (!File.Exists(sFilePath))
fi.CopyTo(sFilePath, true);
}
}
}
}
catch
{ throw; }
}
Hopefully, you'll be able to put the new code to work easier than before! I've left both versions on here just in case .NET 2.0 is out of your reach; though, if pressed, you can use this code in .NET 1.1 with just a little tweaking. Essentially, change the generic Enjoy! Version History
| ||||||||||||||||||||