The code below allows you to copy a directory structure with or without sub folders including files. Also includes a callback that can be used to filter out files or folders and reports the copy progress.
/// <summary>
/// Copies a directory structure to the destination.
/// </summary>
/// <param name="source">The directory structure to be copied.</param>
/// <param name="destination">The destination where the directory structure will be copied to.</param>
/// <param name="copySubDirectories">true to copy all subdirectories.</param>
/// <param name="overwriteFiles">true if the destination files can be overwritten; otherwise, false.</param>
/// <param name="callback">Provides a callback function for reporting progress. </param>
/// <remarks><p>The callback invoked just before a file copy occurs providing a way of being notified.</p>
/// <p>The callback parameter order is source file, destination file, progress.</p>
/// <p>If the callback is specified it should return true to allow the file copy to occur.</p>
/// <p>The progress parameter reports progress from 0 to 100. Values to the left of the decimal represent folder copy progress and values to the
/// right of the decimal from 0.000 to 0.99 represent the current file copy progress for the folder that is being copied.</p>
/// <p>To get the current file copy progress as a value from 0 to 100 use the formula fileProgress = progress - 100 * 100.</p></remarks>
public static void CopyDirectories(string source, string destination, bool copySubDirectories, bool overwriteFiles, Func<string, string, float, bool> callback)
{
// ensure source folder exists
if (!Directory.Exists(source))
{
throw new DirectoryNotFoundException("The path specified in source is invalid (for example, it is on an unmapped drive).");
}
// create destination folder
Directory.CreateDirectory(destination);
// get all files in source and copy them to destination folder
var files = Directory.GetFiles(source);
var progress = 0f; // used to report the progress from 0 to 100
// set up action to copy files
var fileProcessor = new Action<float, string[], string>((folderProgress, filesToCopy, folder) =>
{
// copy files
for (var i = 0; i < filesToCopy.Length; i++)
{
// get file
var file = filesToCopy[i];
// set default result
var result = true;
// build destination filename
var fileName = Path.GetFileName(file);
if (fileName == null) // should never happen
{
return;
}
fileName = Path.Combine(folder, fileName);
// check if callback specified
if (callback != null)
{
// store result from callback
result = callback(file, fileName, progress);
}
// if result is true we are allowed to copy the file
if (result)
{
File.Copy(file, fileName, overwriteFiles);
}
// (folder progress * 100) + file progress
progress = folderProgress + ((float)i / filesToCopy.Length);
}
});
// copy initial files
fileProcessor(0, files, destination);
// check to copy sub directories
if (!copySubDirectories)
{
return;
}
// get the folder tree for the source folder
var folders = Directory.GetDirectories(source, "*.*", SearchOption.AllDirectories);
// process each sub folder
for (var index = 0; index < folders.Length; index++)
{
// get folder and increment index
var folder = folders[index];
// get files
files = Directory.GetFiles(folder);
// crop source root from destination and build destination folder path
folder = folder.Remove(0, source.Length);
folder = Path.Combine(destination, folder);
// create destination folder
Directory.CreateDirectory(folder);
// process file copying
fileProcessor((index / folders.Length) * 100, files, folder);
}
}