My source path is C:\Music\ in which I have hundreds of folders called Album-1, Album-2 etc.
What I want to do is create a folder called Consolidated in my source path.
And then I want to move all the files inside my albums to the folder Consolidated, so that I get all the music files in one folder.
How can I do this?
Try like this
String directoryName = "C:\\Consolidated";
DirectoryInfo dirInfo = new DirectoryInfo(directoryName);
if (dirInfo.Exists == false)
Directory.CreateDirectory(directoryName);
List<String> MyMusicFiles = Directory
.GetFiles("C:\\Music", "*.*", SearchOption.AllDirectories).ToList();
foreach (string file in MyMusicFiles)
{
FileInfo mFile = new FileInfo(file);
// to remove name collisions
if (new FileInfo(dirInfo + "\\" + mFile.Name).Exists == false)
{
mFile.MoveTo(dirInfo + "\\" + mFile.Name);
}
}
It will get all the files in the "C:\Music" folder (including files in the subfolder) and move them to the destination folder. The SearchOption.AllDirectories will recursively search all the subfolders.
Basically, that can be done with Directory.Move:
try
{
Directory.Move(source, destination);
}
catch { }
don't see any reason, why you shouldn't use this function. It's recursive and speed optimized
You can use the Directory object to do this, but you might run into problems if you have the same file name in multiple sub directories (e.g. album1\1.mp3, album2\1.mp3) so you might need a little extra logic to tack something unique onto the names (e.g. album1-1.mp4).
public void CopyDir( string sourceFolder, string destFolder )
{
if (!Directory.Exists( destFolder ))
Directory.CreateDirectory( destFolder );
// Get Files & Copy
string[] files = Directory.GetFiles( sourceFolder );
foreach (string file in files)
{
string name = Path.GetFileName( file );
// ADD Unique File Name Check to Below!!!!
string dest = Path.Combine( destFolder, name );
File.Copy( file, dest );
}
// Get dirs recursively and copy files
string[] folders = Directory.GetDirectories( sourceFolder );
foreach (string folder in folders)
{
string name = Path.GetFileName( folder );
string dest = Path.Combine( destFolder, name );
CopyDir( folder, dest );
}
}
public void MoveDirectory(string[] source, string target)
{
var stack = new Stack<Folders>();
stack.Push(new Folders(source[0], target));
while (stack.Count > 0)
{
var folders = stack.Pop();
Directory.CreateDirectory(folders.Target);
foreach (var file in Directory.GetFiles(folders.Source, "*.*"))
{
string targetFile = Path.Combine(folders.Target, Path.GetFileName(file));
if (File.Exists(targetFile)) File.Delete(targetFile); File.Move(file, targetFile);
}
foreach (var folder in Directory.GetDirectories(folders.Source))
{
stack.Push(new Folders(folder, Path.Combine(folders.Target, Path.GetFileName(folder))));
}
}
Directory.Delete(source[0], true);
}
}
public class Folders {
public string Source {
get; private set;
}
public string Target {
get; private set;
}
public Folders(string source, string target) {
Source = source;
Target = target;
}
}
Something like this should get you rolling. You'll have to add error checking and what not (What if there is a subdirectory of source named "Consolidated"? What if Consolidated already exists? Etc.) This is from memory, so pardon any syntax errors, etc.
string source = #"C:\Music";
string[] directories = Directory.GetDirectories(source);
string consolidated = Path.Combine(source, "Consolidated")
Directory.CreateDirectory(consolidated);
foreach(var directory in directories) {
Directory.Move(directory, consolidated);
}
private static void MoveFiles(string sourceDir, string targetDir)
{
IEnumerable<FileInfo> files = Directory.GetFiles(sourceDir).Select(f => new FileInfo(f));
foreach (var file in files)
{
File.Move(file.FullName, Path.Combine(targetDir, file.Name));
}
}
You'll probably find this helpful to dedup your mp3's that have a different file name but same title.
source from David # msdn!
byte[] b = new byte[128];
string sTitle;
string sSinger;
string sAlbum;
string sYear;
string sComm;
FileStream fs = new FileStream(file, FileMode.Open);
fs.Seek(-128, SeekOrigin.End);
fs.Read(b, 0, 128);
bool isSet = false;
String sFlag = System.Text.Encoding.Default.GetString(b, 0, 3);
if (sFlag.CompareTo("TAG") == 0)
{
System.Console.WriteLine("Tag is setted! ");
isSet = true;
}
if (isSet)
{
//get title of song;
sTitle = System.Text.Encoding.Default.GetString(b, 3, 30);
System.Console.WriteLine("Title: " + sTitle);
//get singer;
sSinger = System.Text.Encoding.Default.GetString(b, 33, 30);
System.Console.WriteLine("Singer: " + sSinger);
//get album;
sAlbum = System.Text.Encoding.Default.GetString(b, 63, 30);
System.Console.WriteLine("Album: " + sAlbum);
//get Year of publish;
sYear = System.Text.Encoding.Default.GetString(b, 93, 4);
System.Console.WriteLine("Year: " + sYear);
//get Comment;
sComm = System.Text.Encoding.Default.GetString(b, 97, 30);
System.Console.WriteLine("Comment: " + sComm);
}
System.Console.WriteLine("Any key to exit! ");
System.Console.Read();
String directoryName = #"D:\NewAll\";
DirectoryInfo dirInfo = new DirectoryInfo(directoryName);
if (dirInfo.Exists == false)
Directory.CreateDirectory(directoryName);
List<String> AllFiles= Directory
.GetFiles(#"D:\SourceDirectory\", "*.*", SearchOption.AllDirectories).ToList();
foreach (string file in AllFiles)
{
FileInfo mFile = new FileInfo(file);
// to remove name collisions
if (new FileInfo(dirInfo + "\\" + mFile.Name).Exists == false)
{
mFile.MoveTo(dirInfo + "\\" + mFile.Name);
}
else
{
string s = mFile.Name.Substring(0, mFile.Name.LastIndexOf('.'));
int a = 0;
while (new FileInfo(dirInfo + "\\" + s + a.ToString() + mFile.Extension).Exists)
{
a++;
}
mFile.MoveTo(dirInfo + "\\" + s + a.ToString() + mFile.Extension);
}
}
ToCopyIt is important to mention that you can't use the ".move()" method across volumes.
https://learn.microsoft.com/en-us/dotnet/api/system.io.file.move?view=net-6.0
https://learn.microsoft.com/en-us/dotnet/api/system.io.directory.move?view=net-6.0
Move files:
string DirFrom = #"C:\MyWork";
string DirTo = #"E:\Archive";
DirectoryInfo DirInfoFrom = new DirectoryInfo(DirFrom);
DirectoryInfo DirInfoTo = new DirectoryInfo(DirTo);
if (!DirInfoTo.Exists)
{
Directory.CreateDirectory(DirTo);
}
foreach (FileInfo FileToCopy in DirInfoFrom.GetFiles())
{
FileToCopy.CopyTo(DirTo + FileToCopy.Name);
File.Delete(FileToCopy.FullName);
}
Tested 1/31/22 .NET4.8 VS2019
Copy all the folders (nested or not) including their files to another folder (destination) with one function call (static void CopyDirectory(string sourceDir, string destinationDir, bool recursive)):
https://learn.microsoft.com/en-us/dotnet/standard/io/how-to-copy-directories
We already had variant for copying directory structure, so this is just modified version of it for moving:
public static void MoveInner(string sourceDirName, string destDirName, bool moveSubDirs)
{
var dir = new DirectoryInfo(sourceDirName);
var dirs = dir.GetDirectories();
// If the source directory does not exist, throw an exception
if (!dir.Exists)
{
throw new DirectoryNotFoundException(
"Source directory does not exist or could not be found: "
+ sourceDirName);
}
// If the destination directory does not exist, create it
if (!Directory.Exists(destDirName))
Directory.CreateDirectory(destDirName);
// Get the file contents of the directory to copy
var files = dir.GetFiles();
foreach (var file in files)
{
// Create the path to the new copy of the file
var temppath = Path.Combine(destDirName, file.Name);
// Move the file.
file.MoveTo(temppath);
}
// If copySubDirs is true, copy the subdirectories
if (!moveSubDirs)
return;
foreach (var subdir in dirs)
{
// Create the subdirectory
var temppath = Path.Combine(destDirName, subdir.Name);
// Move the subdirectories
MoveInner(subdir.FullName, temppath, moveSubDirs: true);
}
}
You loop through them and then simply run Move, the Directory class have functionality for listing contents too iirc.
MSDN : msdn.microsoft.com/en-us/library/bb762914.aspx
private void DirectoryCopy(
string sourceDirName, string destDirName, bool copySubDirs)
{
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
DirectoryInfo[] dirs = dir.GetDirectories();
// If the source directory does not exist, throw an exception.
if (!dir.Exists)
{
throw new DirectoryNotFoundException(
"Source directory does not exist or could not be found: "
+ sourceDirName);
}
// If the destination directory does not exist, create it.
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
// Get the file contents of the directory to copy.
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
// Create the path to the new copy of the file.
string temppath = Path.Combine(destDirName, file.Name);
// Copy the file.
file.CopyTo(temppath, false);
}
// If copySubDirs is true, copy the subdirectories.
if (copySubDirs)
{
foreach (DirectoryInfo subdir in dirs)
{
// Create the subdirectory.
string temppath = Path.Combine(destDirName, subdir.Name);
// Copy the subdirectories.
DirectoryCopy(subdir.FullName, temppath, copySubDirs);
}
}
}
class Program
{
static void Main(string[] args)
{
movedirfiles(#"E:\f1", #"E:\f2");
}
static void movedirfiles(string sourdir,string destdir)
{
string[] dirlist = Directory.GetDirectories(sourdir);
moveallfiles(sourdir, destdir);
if (dirlist!=null && dirlist.Count()>0)
{
foreach(string dir in dirlist)
{
string dirName = destdir+"\\"+ new DirectoryInfo(dir).Name;
Directory.CreateDirectory(dirName);
moveallfiles(dir,dirName);
}
}
}
static void moveallfiles(string sourdir,string destdir)
{
string[] filelist = Directory.GetFiles(sourdir);
if (filelist != null && filelist.Count() > 0)
{
foreach (string file in filelist)
{
File.Copy(file, string.Concat(destdir, "\\"+Path.GetFileName(file)));
}
}
}
}
I want to copy the entire contents of a directory from one location to another in C#.
There doesn't appear to be a way to do this using System.IO classes without lots of recursion.
There is a method in VB that we can use if we add a reference to Microsoft.VisualBasic:
new Microsoft.VisualBasic.Devices.Computer().
FileSystem.CopyDirectory( sourceFolder, outputFolder );
This seems like a rather ugly hack. Is there a better way?
Much easier
private static void CopyFilesRecursively(string sourcePath, string targetPath)
{
//Now Create all of the directories
foreach (string dirPath in Directory.GetDirectories(sourcePath, "*", SearchOption.AllDirectories))
{
Directory.CreateDirectory(dirPath.Replace(sourcePath, targetPath));
}
//Copy all the files & Replaces any files with the same name
foreach (string newPath in Directory.GetFiles(sourcePath, "*.*",SearchOption.AllDirectories))
{
File.Copy(newPath, newPath.Replace(sourcePath, targetPath), true);
}
}
Hmm, I think I misunderstand the question but I'm going to risk it. What's wrong with the following straightforward method?
public static void CopyFilesRecursively(DirectoryInfo source, DirectoryInfo target) {
foreach (DirectoryInfo dir in source.GetDirectories())
CopyFilesRecursively(dir, target.CreateSubdirectory(dir.Name));
foreach (FileInfo file in source.GetFiles())
file.CopyTo(Path.Combine(target.FullName, file.Name));
}
EDIT Since this posting has garnered an impressive number of downvotes for such a simple answer to an equally simple question, let me add an explanation. Please read this before downvoting.
First of all, this code is not intendend as a drop-in replacement to the code in the question. It is for illustration purpose only.
Microsoft.VisualBasic.Devices.Computer.FileSystem.CopyDirectory does some additional correctness tests (e.g. whether the source and target are valid directories, whether the source is a parent of the target etc.) that are missing from this answer. That code is probably also more optimized.
That said, the code works well. It has (almost identically) been used in a mature software for years. Apart from the inherent fickleness present with all IO handlings (e.g. what happens if the user manually unplugs the USB drive while your code is writing to it?), there are no known problems.
In particular, I’d like to point out that the use of recursion here is absolutely not a problem. Neither in theory (conceptually, it’s the most elegant solution) nor in practice: this code will not overflow the stack. The stack is large enough to handle even deeply nested file hierarchies. Long before stack space becomes a problem, the folder path length limitation kicks in.
Notice that a malicious user might be able to break this assumption by using deeply-nested directories of one letter each. I haven’t tried this. But just to illustrate the point: in order to make this code overflow on a typical computer, the directories would have to be nested a few thousand times. This is simply not a realistic scenario.
Copied from MSDN:
using System;
using System.IO;
class CopyDir
{
public static void Copy(string sourceDirectory, string targetDirectory)
{
DirectoryInfo diSource = new DirectoryInfo(sourceDirectory);
DirectoryInfo diTarget = new DirectoryInfo(targetDirectory);
CopyAll(diSource, diTarget);
}
public static void CopyAll(DirectoryInfo source, DirectoryInfo target)
{
Directory.CreateDirectory(target.FullName);
// Copy each file into the new directory.
foreach (FileInfo fi in source.GetFiles())
{
Console.WriteLine(#"Copying {0}\{1}", target.FullName, fi.Name);
fi.CopyTo(Path.Combine(target.FullName, fi.Name), true);
}
// Copy each subdirectory using recursion.
foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
{
DirectoryInfo nextTargetSubDir =
target.CreateSubdirectory(diSourceSubDir.Name);
CopyAll(diSourceSubDir, nextTargetSubDir);
}
}
public static void Main()
{
string sourceDirectory = #"c:\sourceDirectory";
string targetDirectory = #"c:\targetDirectory";
Copy(sourceDirectory, targetDirectory);
}
// Output will vary based on the contents of the source directory.
}
Or, if you want to go the hard way, add a reference to your project for Microsoft.VisualBasic and then use the following:
Microsoft.VisualBasic.FileIO.FileSystem.CopyDirectory(fromDirectory, toDirectory);
However, using one of the recursive functions is a better way to go since it won't have to load the VB dll.
Try this:
Process proc = new Process();
proc.StartInfo.UseShellExecute = true;
proc.StartInfo.FileName = Path.Combine(Environment.SystemDirectory, "xcopy.exe");
proc.StartInfo.Arguments = #"C:\source C:\destination /E /I";
proc.Start();
Your xcopy arguments may vary but you get the idea.
This site always have helped me out a lot, and now it's my turn to help the others with what I know.
I hope that my code below be useful for someone.
string source_dir = #"E:\";
string destination_dir = #"C:\";
// substring is to remove destination_dir absolute path (E:\).
// Create subdirectory structure in destination
foreach (string dir in System.IO.Directory.GetDirectories(source_dir, "*", System.IO.SearchOption.AllDirectories))
{
System.IO.Directory.CreateDirectory(System.IO.Path.Combine(destination_dir, dir.Substring(source_dir.Length + 1)));
// Example:
// > C:\sources (and not C:\E:\sources)
}
foreach (string file_name in System.IO.Directory.GetFiles(source_dir, "*", System.IO.SearchOption.AllDirectories))
{
System.IO.File.Copy(file_name, System.IO.Path.Combine(destination_dir, file_name.Substring(source_dir.Length + 1)));
}
Copy folder recursively without recursion to avoid stack overflow.
public static void CopyDirectory(string source, string target)
{
var stack = new Stack<Folders>();
stack.Push(new Folders(source, target));
while (stack.Count > 0)
{
var folders = stack.Pop();
Directory.CreateDirectory(folders.Target);
foreach (var file in Directory.GetFiles(folders.Source, "*.*"))
{
File.Copy(file, Path.Combine(folders.Target, Path.GetFileName(file)));
}
foreach (var folder in Directory.GetDirectories(folders.Source))
{
stack.Push(new Folders(folder, Path.Combine(folders.Target, Path.GetFileName(folder))));
}
}
}
public class Folders
{
public string Source { get; private set; }
public string Target { get; private set; }
public Folders(string source, string target)
{
Source = source;
Target = target;
}
}
Here's a utility class I've used for IO tasks like this.
using System;
using System.Runtime.InteropServices;
namespace MyNameSpace
{
public class ShellFileOperation
{
private static String StringArrayToMultiString(String[] stringArray)
{
String multiString = "";
if (stringArray == null)
return "";
for (int i=0 ; i<stringArray.Length ; i++)
multiString += stringArray[i] + '\0';
multiString += '\0';
return multiString;
}
public static bool Copy(string source, string dest)
{
return Copy(new String[] { source }, new String[] { dest });
}
public static bool Copy(String[] source, String[] dest)
{
Win32.SHFILEOPSTRUCT FileOpStruct = new Win32.SHFILEOPSTRUCT();
FileOpStruct.hwnd = IntPtr.Zero;
FileOpStruct.wFunc = (uint)Win32.FO_COPY;
String multiSource = StringArrayToMultiString(source);
String multiDest = StringArrayToMultiString(dest);
FileOpStruct.pFrom = Marshal.StringToHGlobalUni(multiSource);
FileOpStruct.pTo = Marshal.StringToHGlobalUni(multiDest);
FileOpStruct.fFlags = (ushort)Win32.ShellFileOperationFlags.FOF_NOCONFIRMATION;
FileOpStruct.lpszProgressTitle = "";
FileOpStruct.fAnyOperationsAborted = 0;
FileOpStruct.hNameMappings = IntPtr.Zero;
int retval = Win32.SHFileOperation(ref FileOpStruct);
if(retval != 0) return false;
return true;
}
public static bool Move(string source, string dest)
{
return Move(new String[] { source }, new String[] { dest });
}
public static bool Delete(string file)
{
Win32.SHFILEOPSTRUCT FileOpStruct = new Win32.SHFILEOPSTRUCT();
FileOpStruct.hwnd = IntPtr.Zero;
FileOpStruct.wFunc = (uint)Win32.FO_DELETE;
String multiSource = StringArrayToMultiString(new string[] { file });
FileOpStruct.pFrom = Marshal.StringToHGlobalUni(multiSource);
FileOpStruct.pTo = IntPtr.Zero;
FileOpStruct.fFlags = (ushort)Win32.ShellFileOperationFlags.FOF_SILENT | (ushort)Win32.ShellFileOperationFlags.FOF_NOCONFIRMATION | (ushort)Win32.ShellFileOperationFlags.FOF_NOERRORUI | (ushort)Win32.ShellFileOperationFlags.FOF_NOCONFIRMMKDIR;
FileOpStruct.lpszProgressTitle = "";
FileOpStruct.fAnyOperationsAborted = 0;
FileOpStruct.hNameMappings = IntPtr.Zero;
int retval = Win32.SHFileOperation(ref FileOpStruct);
if(retval != 0) return false;
return true;
}
public static bool Move(String[] source, String[] dest)
{
Win32.SHFILEOPSTRUCT FileOpStruct = new Win32.SHFILEOPSTRUCT();
FileOpStruct.hwnd = IntPtr.Zero;
FileOpStruct.wFunc = (uint)Win32.FO_MOVE;
String multiSource = StringArrayToMultiString(source);
String multiDest = StringArrayToMultiString(dest);
FileOpStruct.pFrom = Marshal.StringToHGlobalUni(multiSource);
FileOpStruct.pTo = Marshal.StringToHGlobalUni(multiDest);
FileOpStruct.fFlags = (ushort)Win32.ShellFileOperationFlags.FOF_NOCONFIRMATION;
FileOpStruct.lpszProgressTitle = "";
FileOpStruct.fAnyOperationsAborted = 0;
FileOpStruct.hNameMappings = IntPtr.Zero;
int retval = Win32.SHFileOperation(ref FileOpStruct);
if(retval != 0) return false;
return true;
}
}
}
tboswell 's replace Proof version (which is resilient to repeating pattern in filepath)
public static void copyAll(string SourcePath , string DestinationPath )
{
//Now Create all of the directories
foreach (string dirPath in Directory.GetDirectories(SourcePath, "*", SearchOption.AllDirectories))
Directory.CreateDirectory(Path.Combine(DestinationPath ,dirPath.Remove(0, SourcePath.Length )) );
//Copy all the files & Replaces any files with the same name
foreach (string newPath in Directory.GetFiles(SourcePath, "*.*", SearchOption.AllDirectories))
File.Copy(newPath, Path.Combine(DestinationPath , newPath.Remove(0, SourcePath.Length)) , true);
}
My solution is basically a modification of #Termininja's answer, however I have enhanced it a bit and it appears to be more than 5 times faster than the accepted answer.
public static void CopyEntireDirectory(string path, string newPath)
{
Parallel.ForEach(Directory.GetFileSystemEntries(path, "*", SearchOption.AllDirectories)
,(fileName) =>
{
string output = Regex.Replace(fileName, "^" + Regex.Escape(path), newPath);
if (File.Exists(fileName))
{
Directory.CreateDirectory(Path.GetDirectoryName(output));
File.Copy(fileName, output, true);
}
else
Directory.CreateDirectory(output);
});
}
EDIT: Modifying #Ahmed Sabry to full parallel foreach does produce a better result, however the code uses recursive function and its not ideal in some situation.
public static void CopyEntireDirectory(DirectoryInfo source, DirectoryInfo target, bool overwiteFiles = true)
{
if (!source.Exists) return;
if (!target.Exists) target.Create();
Parallel.ForEach(source.GetDirectories(), (sourceChildDirectory) =>
CopyEntireDirectory(sourceChildDirectory, new DirectoryInfo(Path.Combine(target.FullName, sourceChildDirectory.Name))));
Parallel.ForEach(source.GetFiles(), sourceFile =>
sourceFile.CopyTo(Path.Combine(target.FullName, sourceFile.Name), overwiteFiles));
}
It may not be performance-aware, but I'm using it for 30MB folders and it works flawlessly. Plus, I didn't like all the amount of code and recursion required for such an easy task.
var src = "c:\src";
var dest = "c:\dest";
var cmp = CompressionLevel.NoCompression;
var zip = source_folder + ".zip";
ZipFile.CreateFromDirectory(src, zip, cmp, includeBaseDirectory: false);
ZipFile.ExtractToDirectory(zip, dest_folder);
File.Delete(zip);
Note: ZipFile is available on .NET 4.5+ in the System.IO.Compression namespace
Here is a concise and efficient solution:
namespace System.IO {
public static class ExtensionMethods {
public static void CopyTo(this DirectoryInfo srcPath, string destPath) {
Directory.CreateDirectory(destPath);
Parallel.ForEach(srcPath.GetDirectories("*", SearchOption.AllDirectories),
srcInfo => Directory.CreateDirectory($"{destPath}{srcInfo.FullName[srcPath.FullName.Length..]}"));
Parallel.ForEach(srcPath.GetFiles("*", SearchOption.AllDirectories),
srcInfo => File.Copy(srcInfo.FullName, $"{destPath}{srcInfo.FullName[srcPath.FullName.Length..]}", true));
});
}
}
}
To use:
new DirectoryInfo(sourcePath).CopyTo(destinationPath);
A minor improvement on d4nt's answer, as you probably want to check for errors and not have to change xcopy paths if you're working on a server and development machine:
public void CopyFolder(string source, string destination)
{
string xcopyPath = Environment.GetEnvironmentVariable("WINDIR") + #"\System32\xcopy.exe";
ProcessStartInfo info = new ProcessStartInfo(xcopyPath);
info.UseShellExecute = false;
info.RedirectStandardOutput = true;
info.Arguments = string.Format("\"{0}\" \"{1}\" /E /I", source, destination);
Process process = Process.Start(info);
process.WaitForExit();
string result = process.StandardOutput.ReadToEnd();
if (process.ExitCode != 0)
{
// Or your own custom exception, or just return false if you prefer.
throw new InvalidOperationException(string.Format("Failed to copy {0} to {1}: {2}", source, destination, result));
}
}
This is my code hope this help
private void KCOPY(string source, string destination)
{
if (IsFile(source))
{
string target = Path.Combine(destination, Path.GetFileName(source));
File.Copy(source, target, true);
}
else
{
string fileName = Path.GetFileName(source);
string target = System.IO.Path.Combine(destination, fileName);
if (!System.IO.Directory.Exists(target))
{
System.IO.Directory.CreateDirectory(target);
}
List<string> files = GetAllFileAndFolder(source);
foreach (string file in files)
{
KCOPY(file, target);
}
}
}
private List<string> GetAllFileAndFolder(string path)
{
List<string> allFile = new List<string>();
foreach (string dir in Directory.GetDirectories(path))
{
allFile.Add(dir);
}
foreach (string file in Directory.GetFiles(path))
{
allFile.Add(file);
}
return allFile;
}
private bool IsFile(string path)
{
if ((File.GetAttributes(path) & FileAttributes.Directory) == FileAttributes.Directory)
{
return false;
}
return true;
}
If you like Konrad's popular answer, but you want the source itself to be a folder under target, rather than putting it's children under the target folder, here's the code for that. It returns the newly created DirectoryInfo, which is handy:
public static DirectoryInfo CopyFilesRecursively(DirectoryInfo source, DirectoryInfo target)
{
var newDirectoryInfo = target.CreateSubdirectory(source.Name);
foreach (var fileInfo in source.GetFiles())
fileInfo.CopyTo(Path.Combine(newDirectoryInfo.FullName, fileInfo.Name));
foreach (var childDirectoryInfo in source.GetDirectories())
CopyFilesRecursively(childDirectoryInfo, newDirectoryInfo);
return newDirectoryInfo;
}
You can always use this, taken from Microsofts website.
static void Main()
{
// Copy from the current directory, include subdirectories.
DirectoryCopy(".", #".\temp", true);
}
private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
{
// Get the subdirectories for the specified directory.
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
if (!dir.Exists)
{
throw new DirectoryNotFoundException(
"Source directory does not exist or could not be found: "
+ sourceDirName);
}
DirectoryInfo[] dirs = dir.GetDirectories();
// If the destination directory doesn't exist, create it.
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
// Get the files in the directory and copy them to the new location.
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
string temppath = Path.Combine(destDirName, file.Name);
file.CopyTo(temppath, false);
}
// If copying subdirectories, copy them and their contents to new location.
if (copySubDirs)
{
foreach (DirectoryInfo subdir in dirs)
{
string temppath = Path.Combine(destDirName, subdir.Name);
DirectoryCopy(subdir.FullName, temppath, copySubDirs);
}
}
}
Sorry for the previous code, it still had bugs :( (fell prey to the fastest gun problem) . Here it is tested and working. The key is the SearchOption.AllDirectories, which eliminates the need for explicit recursion.
string path = "C:\\a";
string[] dirs = Directory.GetDirectories(path, "*.*", SearchOption.AllDirectories);
string newpath = "C:\\x";
try
{
Directory.CreateDirectory(newpath);
}
catch (IOException ex)
{
Console.WriteLine(ex.Message);
}
for (int j = 0; j < dirs.Length; j++)
{
try
{
Directory.CreateDirectory(dirs[j].Replace(path, newpath));
}
catch (IOException ex)
{
Console.WriteLine(ex.Message);
}
}
string[] files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
for (int j = 0; j < files.Length; j++)
{
try
{
File.Copy(files[j], files[j].Replace(path, newpath));
}
catch (IOException ex)
{
Console.WriteLine(ex.Message);
}
}
Here is an extension method for DirectoryInfo a la FileInfo.CopyTo (note the overwrite parameter):
public static DirectoryInfo CopyTo(this DirectoryInfo sourceDir, string destinationPath, bool overwrite = false)
{
var sourcePath = sourceDir.FullName;
var destination = new DirectoryInfo(destinationPath);
destination.Create();
foreach (var sourceSubDirPath in Directory.EnumerateDirectories(sourcePath, "*", SearchOption.AllDirectories))
Directory.CreateDirectory(sourceSubDirPath.Replace(sourcePath, destinationPath));
foreach (var file in Directory.EnumerateFiles(sourcePath, "*", SearchOption.AllDirectories))
File.Copy(file, file.Replace(sourcePath, destinationPath), overwrite);
return destination;
}
Use this class.
public static class Extensions
{
public static void CopyTo(this DirectoryInfo source, DirectoryInfo target, bool overwiteFiles = true)
{
if (!source.Exists) return;
if (!target.Exists) target.Create();
Parallel.ForEach(source.GetDirectories(), (sourceChildDirectory) =>
CopyTo(sourceChildDirectory, new DirectoryInfo(Path.Combine(target.FullName, sourceChildDirectory.Name))));
foreach (var sourceFile in source.GetFiles())
sourceFile.CopyTo(Path.Combine(target.FullName, sourceFile.Name), overwiteFiles);
}
public static void CopyTo(this DirectoryInfo source, string target, bool overwiteFiles = true)
{
CopyTo(source, new DirectoryInfo(target), overwiteFiles);
}
}
One variant with only one loop for copying of all folders and files:
foreach (var f in Directory.GetFileSystemEntries(path, "*", SearchOption.AllDirectories))
{
var output = Regex.Replace(f, #"^" + path, newPath);
if (File.Exists(f)) File.Copy(f, output, true);
else Directory.CreateDirectory(output);
}
Better than any code (extension method to DirectoryInfo with recursion)
public static bool CopyTo(this DirectoryInfo source, string destination)
{
try
{
foreach (string dirPath in Directory.GetDirectories(source.FullName))
{
var newDirPath = dirPath.Replace(source.FullName, destination);
Directory.CreateDirectory(newDirPath);
new DirectoryInfo(dirPath).CopyTo(newDirPath);
}
//Copy all the files & Replaces any files with the same name
foreach (string filePath in Directory.GetFiles(source.FullName))
{
File.Copy(filePath, filePath.Replace(source.FullName,destination), true);
}
return true;
}
catch (IOException exp)
{
return false;
}
}
Copy and replace all files of the folder
public static void CopyAndReplaceAll(string SourcePath, string DestinationPath, string backupPath)
{
foreach (string dirPath in Directory.GetDirectories(SourcePath, "*", SearchOption.AllDirectories))
{
Directory.CreateDirectory($"{DestinationPath}{dirPath.Remove(0, SourcePath.Length)}");
Directory.CreateDirectory($"{backupPath}{dirPath.Remove(0, SourcePath.Length)}");
}
foreach (string newPath in Directory.GetFiles(SourcePath, "*.*", SearchOption.AllDirectories))
{
if (!File.Exists($"{ DestinationPath}{newPath.Remove(0, SourcePath.Length)}"))
File.Copy(newPath, $"{ DestinationPath}{newPath.Remove(0, SourcePath.Length)}");
else
File.Replace(newPath
, $"{ DestinationPath}{newPath.Remove(0, SourcePath.Length)}"
, $"{ backupPath}{newPath.Remove(0, SourcePath.Length)}", false);
}
}
The code below is microsoft suggestion how-to-copy-directories
and it is shared by dear #iato
but it just copies sub directories and files of source folder recursively and doesn't copy the source folder it self (like right click -> copy ).
but there is a tricky way below this answer :
private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs = true)
{
// Get the subdirectories for the specified directory.
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
if (!dir.Exists)
{
throw new DirectoryNotFoundException(
"Source directory does not exist or could not be found: "
+ sourceDirName);
}
DirectoryInfo[] dirs = dir.GetDirectories();
// If the destination directory doesn't exist, create it.
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
// Get the files in the directory and copy them to the new location.
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
string temppath = Path.Combine(destDirName, file.Name);
file.CopyTo(temppath, false);
}
// If copying subdirectories, copy them and their contents to new location.
if (copySubDirs)
{
foreach (DirectoryInfo subdir in dirs)
{
string temppath = Path.Combine(destDirName, subdir.Name);
DirectoryCopy(subdir.FullName, temppath, copySubDirs);
}
}
}
if you want to copy contents of source folder and subfolders recursively you can simply use it like this :
string source = #"J:\source\";
string dest= #"J:\destination\";
DirectoryCopy(source, dest);
but if you want to copy the source directory it self (similar that you have right clicked on source folder and clicked copy then in the destination folder you clicked paste) you should use like this :
string source = #"J:\source\";
string dest= #"J:\destination\";
DirectoryCopy(source, Path.Combine(dest, new DirectoryInfo(source).Name));
Below code to copy all files from source to destination of given pattern in same folder structure:
public static void Copy()
{
string sourceDir = #"C:\test\source\";
string destination = #"C:\test\destination\";
string[] textFiles = Directory.GetFiles(sourceDir, "*.txt", SearchOption.AllDirectories);
foreach (string textFile in textFiles)
{
string fileName = textFile.Substring(sourceDir.Length);
string directoryPath = Path.Combine(destination, Path.GetDirectoryName(fileName));
if (!Directory.Exists(directoryPath))
Directory.CreateDirectory(directoryPath);
File.Copy(textFile, Path.Combine(directoryPath, Path.GetFileName(textFile)), true);
}
}
Just wanted to add my version. It can handle both directories and files, and can overwrite or skip if destination file exists.
public static void Copy(
string source,
string destination,
string pattern = "*",
bool includeSubFolders = true,
bool overwrite = true,
bool overwriteOnlyIfSourceIsNewer = false)
{
if (File.Exists(source))
{
// Source is a file, copy and leave
CopyFile(source, destination);
return;
}
if (!Directory.Exists(source))
{
throw new DirectoryNotFoundException($"Source directory does not exists: `{source}`");
}
var files = Directory.GetFiles(
source,
pattern,
includeSubFolders ?
SearchOption.AllDirectories :
SearchOption.TopDirectoryOnly);
foreach (var file in files)
{
var newFile = file.Replace(source, destination);
CopyFile(file, newFile, overwrite, overwriteOnlyIfSourceIsNewer);
}
}
private static void CopyFile(
string source,
string destination,
bool overwrite = true,
bool overwriteIfSourceIsNewer = false)
{
if (!overwrite && File.Exists(destination))
{
return;
}
if (overwriteIfSourceIsNewer && File.Exists(destination))
{
var sourceLastModified = File.GetLastWriteTimeUtc(source);
var destinationLastModified = File.GetLastWriteTimeUtc(destination);
if (sourceLastModified <= destinationLastModified)
{
return;
}
CreateDirectory(destination);
File.Copy(source, destination, overwrite);
return;
}
CreateDirectory(destination);
File.Copy(source, destination, overwrite);
}
private static void CreateDirectory(string filePath)
{
var targetDirectory = Path.GetDirectoryName(filePath);
if (targetDirectory != null && !Directory.Exists(targetDirectory))
{
Directory.CreateDirectory(targetDirectory);
}
}
Properties of this code:
No parallel task, is less performant, but the idea is to treat file by file, so you can log or stop.
Can skip hiddden files
Can skip by modified date
Can break or not (you chose) on a file copy error
Uses Buffer of 64K for SMB and FileShare.ReadWrite to avoid locks
Personalize your Exceptions Message
For Windows
Notes
ExceptionToString() is a personal extension that tries to get inner exceptions and display stack. Replace it for ex.Message or any other code.
log4net.ILog _log I use ==Log4net== You can make your Log in a different way.
/// <summary>
/// Recursive Directory Copy
/// </summary>
/// <param name="fromPath"></param>
/// <param name="toPath"></param>
/// <param name="continueOnException">on error, continue to copy next file</param>
/// <param name="skipHiddenFiles">To avoid files like thumbs.db</param>
/// <param name="skipByModifiedDate">Does not copy if the destiny file has the same or more recent modified date</param>
/// <remarks>
/// </remarks>
public static void CopyEntireDirectory(string fromPath, string toPath, bool continueOnException = false, bool skipHiddenFiles = true, bool skipByModifiedDate = true)
{
log4net.ILog _log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
string nl = Environment.NewLine;
string sourcePath = "";
string destPath = "";
string _exMsg = "";
void TreateException(Exception ex)
{
_log.Warn(_exMsg);
if (continueOnException == false)
{
throw new Exception($"{_exMsg}{nl}----{nl}{ex.ExceptionToString()}");
}
}
try
{
foreach (string fileName in Directory.GetFileSystemEntries(fromPath, "*", SearchOption.AllDirectories))
{
sourcePath = fileName;
destPath = Regex.Replace(fileName, "^" + Regex.Escape(fromPath), toPath);
Directory.CreateDirectory(Path.GetDirectoryName(destPath));
_log.Debug(FileCopyStream(sourcePath, destPath,skipHiddenFiles,skipByModifiedDate));
}
}
// Directory must be less than 148 characters, File must be less than 261 characters
catch (PathTooLongException)
{
throw new Exception($"Both paths must be less than 148 characters:{nl}{sourcePath}{nl}{destPath}");
}
// Not enough disk space. Cancel further copies
catch (IOException ex) when ((ex.HResult & 0xFFFF) == 0x27 || (ex.HResult & 0xFFFF) == 0x70)
{
throw new Exception($"Not enough disk space:{nl}'{toPath}'");
}
// used by another process
catch (IOException ex) when ((uint)ex.HResult == 0x80070020)
{
_exMsg = $"File is being used by another process:{nl}'{destPath}'{nl}{ex.Message}";
TreateException(ex);
}
catch (UnauthorizedAccessException ex)
{
_exMsg = $"Unauthorized Access Exception:{nl}from:'{sourcePath}'{nl}to:{destPath}";
TreateException(ex);
}
catch (Exception ex)
{
_exMsg = $"from:'{sourcePath}'{nl}to:{destPath}";
TreateException(ex);
}
}
/// <summary>
/// File Copy using Stream 64K and trying to avoid locks with fileshare
/// </summary>
/// <param name="sourcePath"></param>
/// <param name="destPath"></param>
/// <param name="skipHiddenFiles">To avoid files like thumbs.db</param>
/// <param name="skipByModifiedDate">Does not copy if the destiny file has the same or more recent modified date</param>
public static string FileCopyStream(string sourcePath, string destPath, bool skipHiddenFiles = true, bool skipByModifiedDate = true)
{
// Buffer should be 64K = 65536 bytes
// Increasing the buffer size beyond 64k will not help in any circunstance,
// as the underlying SMB protocol does not support buffer lengths beyond 64k."
byte[] buffer = new byte[65536];
if (!File.Exists(sourcePath))
return $"is not a file: '{sourcePath}'";
FileInfo sourcefileInfo = new FileInfo(sourcePath);
FileInfo destFileInfo = null;
if (File.Exists(destPath))
destFileInfo = new FileInfo(destPath);
if (skipHiddenFiles)
{
if (sourcefileInfo.Attributes.HasFlag(FileAttributes.Hidden))
return $"Hidden File Not Copied: '{sourcePath}'";
}
using (FileStream input = sourcefileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (FileStream output = new FileStream(destPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite, buffer.Length))
{
if (skipByModifiedDate && destFileInfo != null)
{
if (destFileInfo.LastWriteTime < sourcefileInfo.LastWriteTime)
{
input.CopyTo(output, buffer.Length);
destFileInfo.LastWriteTime = sourcefileInfo.LastWriteTime;
return $"Replaced: '{sourcePath}'";
}
else
{
return $"NOT replaced (more recent or same file): '{sourcePath}'";
}
}
else
{
input.CopyTo(output, buffer.Length);
destFileInfo = new FileInfo(destPath);
destFileInfo.LastWriteTime = sourcefileInfo.LastWriteTime;
return $"New File: '{sourcePath}'";
}
}
}
For UWP and Winui 3 (WindowsAppSdk) using Async API:
public async Task CopyAsync(StorageFolder source, StorageFolder dest)
{
foreach (var item in await source.GetItemsAsync())
if (item is StorageFile file)
await file.CopyAsync(dest);
else if (item is StorageFolder folder)
await CopyAsync(folder, await dest.CreateFolderAsync(folder.Name, CreationCollisionOption.OpenIfExists));
}
public static class Extensions
{
public static void Copy(this DirectoryInfo self, DirectoryInfo destination, bool recursively)
{
foreach (var file in self.GetFiles())
{
file.CopyTo(Path.Combine(destination.FullName, file.Name));
}
if (recursively)
{
foreach (var directory in self.GetDirectories())
{
directory.Copy(destination.CreateSubdirectory(directory.Name), recursively);
}
}
}
}
Example of use:
var sourceDirectory = new DirectoryInfo(#"C:\source");
var destinationDirectory = new DirectoryInfo(#"C:\destination");
if (destinationDirectory.Exists == false)
{
sourceDirectory.Copy(destinationDirectory, recursively: true);
}