public static class IOExtensions {
public static void CopyTo(this DirectoryInfo source, DirectoryInfo destination, bool recursive = false, Regex? pattern = null, bool negatePattern = false) {
if (destination.FullName.StartsWith(source.FullName))
throw new InvalidOperationException("The target directory must not be inside the source directory");
if (!source.Exists)
throw new DirectoryNotFoundException($"Source directory not found: '{source.FullName}'");
if (!destination.Exists) {
destination.Create();
} else if (destination.EnumerateFiles("*", SearchOption.AllDirectories).Any()){
throw new IOException("Target directory not empty");
}
List<Exception> exceptions = new List<Exception>();
foreach(var subInfo in source.EnumerateFileSystemInfos().Where(i => pattern != null ? (negatePattern ? !pattern.IsMatch(i.Name) : pattern.IsMatch(i.Name)) : true)){
try {
var destinationPath = Path.Combine(destination.FullName, subInfo.Name);
if (subInfo is DirectoryInfo) {
if (recursive) {
((DirectoryInfo)subInfo).CopyTo(new DirectoryInfo(destinationPath), recursive);
} else {
new DirectoryInfo(destinationPath).Create();
}
} else if (subInfo is FileInfo) {
((FileInfo)subInfo).CopyTo(destinationPath, false);
}
} catch (Exception ex) {
exceptions.Add(ex);
}
}
if (exceptions.Any()) {
throw new AggregateException("Copying files completed with errors", exceptions);
}
}
}