I am trying to make a program to backup files from a particular folder, along with the files within the subfolders of the main folder to another backup folder.
This is part of the code I am trying to accomplish the goal, however I am getting backed up only the files from the main folder, and the subfolders are being copied entirely(all of the files in them).
public static string[] Backup(string sourceDirectory, string targetDirectory, string backupDirectory)
{
DirectoryInfo diBackup = new DirectoryInfo(backupDirectory);
DirectoryInfo diTarget = new DirectoryInfo(targetDirectory);
List<string> dups = new List<string>();
string[] fileNamesSource = Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories);
string[] fileNamesDest = Directory.GetFiles(targetDirectory, "*", SearchOption.AllDirectories);
List<string> dupNS = new List<string>();
List<string> dupND = new List<string>();
List<string> BCKP = new List<string>();
string replacement = "";
for (int i = 0; i < fileNamesDest.Length; i++)
{
string res = fileNamesDest[i].Replace(targetDirectory, replacement);
dupND.Add(res);
}
foreach (var ns in fileNamesSource)
{
string res = ns.Replace(sourceDirectory, replacement);
dupNS.Add(res);
}
var duplicates = dupND.Intersect(dupNS);
string[] DuplicatesStringArray = duplicates.ToArray();
foreach (var dup in DuplicatesStringArray)
{
string res = targetDirectory + dup;
BCKP.Add(res);
}
string[] ToBeBackedUp = BCKP.ToArray();
Directory.CreateDirectory(diBackup.FullName);
// Copy each file into the new directory.
foreach (FileInfo fi in diTarget.GetFiles())
{
if (ToBeBackedUp.Contains(fi.FullName)){
fi.CopyTo(Path.Combine(diBackup.FullName, fi.Name), true);
}
}
// Copy each subdirectory using recursion.
foreach (DirectoryInfo diSourceSubDir in diTarget.GetDirectories())
{
if (ToBeBackedUp.Contains(diSourceSubDir.FullName)) {
DirectoryInfo nextTargetSubDir =
diBackup.CreateSubdirectory(diSourceSubDir.Name);
CopyAll(diSourceSubDir, nextTargetSubDir);
}
}
return ToBeBackedUp;
}
Any ideas of how can I copy only the files in the subfolders that exist in the "source" folder?
Also the CopyAll function:
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())
{
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);
}
}
Thanks in advance.
You can try this way as
Much easier
//Now Create all of the directories
foreach (string dirPath in Directory.GetDirectories(SourcePath, "*",
SearchOption.AllDirectories))
Directory.CreateDirectory(dirPath.Replace(SourcePath, DestinationPath));
//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, DestinationPath), true);
A simple solution: in your CopyAll method, load the SearchOption.AllDirectories argument to your GetFiles method:
foreach (FileInfo fi in source.GetFiles("*", SearchOption.AllDirectories))
{
fi.CopyTo(Path.Combine(target.FullName, fi.Name), true);
}
You can use Directory.GetFiles along with SearchOption.AllDirectories to extract the files from the sub-folders as well:
Directory.GetFiles(path, *search pattern goes here*, SearchOption.AllDirectories)
Related
Good day.
I have to copy all the files in folders (including sub folders) to other shared drive location for backup the data. The challenge, which I am facing is folder path with wildcard characters.
For example,
The folder structure is like below
D:/Folder1/Folder11/Folder111
D:/Folder2/Folder222/Folder222222
D:/Folder3/Folder333333/Folder3333333
I am looking for the input format should be "D:/Folder?/Folder*/Folder*". So that it has to loop according to the wildcard character patterns.
Can you please help me.
Regards,
Chandra
You can achive this with a simple RegularExpression. I've created an example which does the job for you.
The RegEx string is quite easy: [A-Z]:\\Folder[0-9]{1}\\Folder[0-9]{2}\\Folder[0-9]{3}
[A-Z]:\\Folder[0-9]{1}\\Folder[0-9]{2}\\Folder[0-9]{3}
----- -------- -------- --------
Drive 1x digit 2x digit 3x digit
See the sample at regexr.
EDIT:
//using System.IO;
public void CopyMatching(string drive)
{
try
{
var backuplocation = ""; //the path where you wanna copy your files to
var regex = new Regex(#"[A-Z]:\\Folder[0-9]{1}\\Folder[0-9]{2}\\Folder[0-9]{3}");
var directories = new List<string>();
foreach (var directory in Directory.EnumerateDirectories(drive))
{
if (regex.IsMatch(directory))
{
directories.Add(directory);
}
}
foreach (var directory in directories)
{
DirectoryCopy(directory, backuplocation, true);
}
}
catch (Exception)
{
throw;
}
}
And DirectoryCopy:
public 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);
}
}
}
IEnumerable<string> getMatchingSubDir(string dirPath, string pattern)
{
List<string> matchingFolders = new List<string>();
DirectoryInfo myDir = new DirectoryInfo(dirPath);
foreach (var subDir in myDir.GetDirectories(pattern))
{
matchingFolders.AddRange(getMatchingSubDir(subDir.FullName, pattern));
}
return matchingFolders;
}
Then this call will return you a list of all folders matching your pattern:
getMatchingSubDir("D:\\", "Folder*");
I have a location like: C:\Backups
I have multiple locations such as:
C:\Users\Peter\Books
C:\ProgramData\Library
C:\Tests\Testing\Tester\
How can I copy everything in each of the locations to the backup location, so that If I drop everything in the backup location folder into C: it will overwrite all the files there with the backup? Basically how can I create the entire structure for backup.
So Far:
public void Init()
{
_locationsToBackup = new List<string>();
DataSet dataSet = _settings.Pull();// dataset is set here
DataTable settingsTable = dataSet.Tables[0];
int valueIndex = 0;
foreach (DataColumn coll in settingsTable.Columns)
{
if (coll.ColumnName == "Value")
{
break;
}
valueIndex++;
}
foreach (DataRow row in settingsTable.Rows)
{
int start = 0;
foreach (DataColumn col in settingsTable.Columns)
{
if (col.ColumnName == "SettingType")
{
string settingRowValue = row.ItemArray[start].ToString();
int settingType = Convert.ToInt32(settingRowValue);
if (settingType == 3)
{
String location = row.ItemArray[valueIndex].ToString();
AddNewLocationToBackup(location);
break;
}
}
start++;
}
}
}
public void StartBackup()
{
//make sure backup folder exists in correct location
// if not then create it.
if(!Directory.Exists(#"C:\ProgramData\Test\Backups"))
{
Directory.CreateDirectory(#"C:\ProgramData\Test\Backups");
}
foreach(string currentLocation in LocationsToBackup)
{
if (Directory.Exists(currentLocation))
{
// copy all files from currentLocation and put into backups
CopyFilesToDirWithSamePath(currentLocation, #"C:\ProgramData\Test\Backups" + #"\" + currentLocation);
}
}
}
}
public void CopyFilesToDirWithSamePath(string sourceDirInput, string targetDirInput)
{
string sourceDir = sourceDirInput;
string targetDir = targetDirInput;
foreach (var file in Directory.GetFiles(sourceDir))
{
File.Copy(file, System.IO.Path.Combine(targetDir, System.IO.Path.GetFileName(file)), true);
}
}
//Now Create all of the directories
foreach (string dirPath in Directory.GetDirectories(SourcePath, "*",
SearchOption.AllDirectories))
Directory.CreateDirectory(dirPath.Replace(SourcePath, DestinationPath));
//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, DestinationPath), true);
I hope this will help you
private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
{
// Get the subdirectories for the specified directory.
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
DirectoryInfo[] dirs = dir.GetDirectories();
if (!dir.Exists)
{
throw new DirectoryNotFoundException(
"Source directory does not exist or could not be found: "
+ sourceDirName);
}
// 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);
}
}
}
I use FileSelectionManager library, take a look to this example:
http://www.fileselectionmanager.com/#Copying%20and%20moving%20files
Hope it hepls.
Is there any way to exclude certain directories from SearchOption using LINQ command like this
string path = "C:\SomeFolder";
var s1 = Directory.GetFiles(path , "*.*", SearchOption.AllDirectories);
var s2 = Directory.GetDirectories(path , "*.*", SearchOption.AllDirectories);
The path consists of Sub1 and Sub2 Folders with certain files in it. I need to exclude them from directory search.
Thanks
This Worked:
string[] exceptions = new string[] { "c:\\SomeFolder\\sub1",
"c:\\SomeFolder\\sub2" };
var s1 = Directory.GetFiles("c:\\x86", "*.*",
SearchOption.AllDirectories).Where(d => exceptions.All(e =>
!d.StartsWith(e)));
This helped with Exceptions
No there isn't as far as I know. But you could use very simple LINQ to do that in a single line.
var s1 = Directory.GetFiles(path , "*.*", SearchOption.AllDirectories).Where(d => !d.StartsWith("<EXCLUDE_DIR_PATH>")).ToArray();
You can easily combine multiple exclude DIRs too.
You can't do exactly what you want with simple LINQ methods. You will need to write a recursive routine instead of using SearchOption.AllDirectories. The reason is that you want to filter directories not files.
You could use the following static method to achieve what you want:
public static IEnumerable<string> GetFiles(
string rootDirectory,
Func<string, bool> directoryFilter,
string filePattern)
{
foreach (string matchedFile in Directory.GetFiles(rootDirectory, filePattern, SearchOption.TopDirectoryOnly))
{
yield return matchedFile;
}
var matchedDirectories = Directory.GetDirectories(rootDirectory, "*.*", SearchOption.TopDirectoryOnly)
.Where(directoryFilter);
foreach (var dir in matchedDirectories)
{
foreach (var file in GetFiles(dir, directoryFilter, filePattern))
{
yield return file;
}
}
}
You would use it like this:
var files = GetFiles("C:\\SearchDirectory", d => !d.Contains("AvoidMe", StringComparison.OrdinalIgnoreCase), "*.*");
Why the added complexity? This method completely avoids looking inside directories you're not interested in. The SearchOption.AllDirectories will, as the name suggests, search within all directories.
If you're not familiar with iterator methods (the yield return syntax), this can be written differently: just ask!
Alternative
This has almost the same effect. However, it still finds files within subdirectories of the directories you want to ignore. Maybe that's OK for you; the code is easier to follow.
public static IEnumerable<string> GetFilesLinq(
string root,
Func<string, bool> directoryFilter,
string filePattern)
{
var directories = Directory.GetDirectories(root, "*.*", SearchOption.AllDirectories)
.Where(directoryFilter);
List<string> results = new List<string>();
foreach (var d in directories)
{
results.AddRange(Directory.GetFiles(d, filePattern, SearchOption.TopDirectoryOnly));
}
return results;
}
try this
var s2 = Directory.GetDirectories(dirPath, "*", SearchOption.AllDirectories)
.Where(directory => !directory.Contains("DirectoryName"));
///used To Load Files And Folder information Present In Dir In dir
private void button1_Click(object sender, EventArgs e)
{
FileInfo[] fileInfoArr;
StringBuilder sbr=new StringBuilder();
StringBuilder sbrfname = new StringBuilder();
string strpathName = #"C:\Users\prasad\Desktop\Dll";
DirectoryInfo dir = new DirectoryInfo(strpathName);
fileInfoArr = dir.GetFiles("*.dll");
//Load Files From RootFolder
foreach (FileInfo f in fileInfoArr)
{
sbrfname.AppendLine(f.FullName);
}
DirectoryInfo[] dirInfos = dir.GetDirectories("*.*");
//Load Files from folder folder
foreach (DirectoryInfo d in dirInfos)
{
fileInfoArr = d.GetFiles("*.dll");
foreach (FileInfo f in fileInfoArr)
{
sbrfname.AppendLine(f.FullName);
}
sbr.AppendLine(d.ToString());
}
richTextBox1.Text = sbr.ToString();
richTextBox2.Text = sbrfname.ToString();
}
This question already has answers here:
Get all sub directories that only contain files
(4 answers)
Closed 9 years ago.
How can I get files from sub-directories as well, using this code only gets the job done for files under the directory listed:
DirectoryInfo selDir = new DirectoryInfo(folderBrowserDialog1.SelectedPath);
Directory.CreateDirectory(folderBrowserDialog1.SelectedPath + "\\Output");
foreach (FileInfo d in selDir.GetFiles())
{
//my code
}
var allFiles = selDir.GetFiles("*.*", SearchOption.AllDirectories);
I usually make a recurring method to do this. Example:
private void getFiles(string directory)
{
string[] files = Directory.GetFiles(directory);
string[] directories = Directory.GetDirectories(directory);
foreach (string file in files)
{
// Code here.
}
foreach (string subDirectory in directories)
{
// Call the same method on each directory.
getFiles(subDirectory);
}
}
You have the DirectoryInfo of your desired folder, so loop over all it's directories, then you can get the files for each.
DirectoryInfo selDir = new DirectoryInfo(folderBrowserDialog1.SelectedPath);
Directory.CreateDirectory(Path.Combine(folderBrowserDialog1.SelectedPath, "Output"));
foreach (string dir in System.IO.Directory.GetDirectories(selDir.FullName, "*.*", System.IO.SearchOption.AllDirectories))
{
foreach (string file in Directory.GetFiles(dir))
{
//my code
}
}
DirectoryInfo selDir = new DirectoryInfo(folderBrowserDialog1.SelectedPath);
Directory.CreateDirectory(folderBrowserDialog1.SelectedPath + "\\Output");
string[] files = Directory.GetFiles(selDir.FullName, "*.*", SearchOption.AllDirectories);
foreach (string file in files)
{
// your code
}
I found a small snippet for doing a recursive file copy in C#, but am somewhat stumped. I basically need to copy a directory structure to another location, along the lines of this...
Source: C:\data\servers\mc
Target: E:\mc
The code for my copy function as of right now is...
//Now Create all of the directories
foreach (string dirPath in Directory.GetDirectories(baseDir, "*", SearchOption.AllDirectories))
{
Directory.CreateDirectory(dirPath.Replace(baseDir, targetDir));
}
// Copy each file into it’s new directory.
foreach (string file in Directory.GetFiles(baseDir, "*.*", SearchOption.AllDirectories))
{
Console.WriteLine(#"Copying {0}\{1}", targetDir, Path.GetFileName(file));
if (!CopyFile(file, Path.Combine(targetDir, Path.GetFileName(file)), false))
{
int err = Marshal.GetLastWin32Error();
Console.WriteLine("[ERROR] CopyFile Failed on {0} with code {1}", file, err);
}
}
The issue is that in the second scope, I either:
use Path.GetFileName(file) to get the actual file name without the path but I lose the directory "mc" directory structure or
use "file" without Path.Combine.
Either way I have to do some nasty string work. Is there a good way to do this in C# (my lack of knowledge with the .NET API leads me to over complicating things)
MSDN has a complete sample: How to: copy directories
using System;
using System.IO;
class DirectoryCopyExample
{
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);
}
}
}
}
A non-recursive replacement for this answer would be:
private static void DirectoryCopy(string sourceBasePath, string destinationBasePath, bool recursive = true)
{
if (!Directory.Exists(sourceBasePath))
throw new DirectoryNotFoundException($"Directory '{sourceBasePath}' not found");
var directoriesToProcess = new Queue<(string sourcePath, string destinationPath)>();
directoriesToProcess.Enqueue((sourcePath: sourceBasePath, destinationPath: destinationBasePath));
while (directoriesToProcess.Any())
{
(string sourcePath, string destinationPath) = directoriesToProcess.Dequeue();
if (!Directory.Exists(destinationPath))
Directory.CreateDirectory(destinationPath);
var sourceDirectoryInfo = new DirectoryInfo(sourcePath);
foreach (FileInfo sourceFileInfo in sourceDirectoryInfo.EnumerateFiles())
sourceFileInfo.CopyTo(Path.Combine(destinationPath, sourceFileInfo.Name), true);
if (!recursive)
continue;
foreach (DirectoryInfo sourceSubDirectoryInfo in sourceDirectoryInfo.EnumerateDirectories())
directoriesToProcess.Enqueue((
sourcePath: sourceSubDirectoryInfo.FullName,
destinationPath: Path.Combine(destinationPath, sourceSubDirectoryInfo.Name)));
}
}
instead of
foreach (string file in Directory.GetFiles(baseDir, "*.*", SearchOption.AllDirectories))
{
do something like this
foreach (FileInfo fi in source.GetFiles())
{
fi.CopyTo(Path.Combine(target.ToString(), fi.Name), true);
}