I'm learning c# and i have a task to:
Sync content of the two directories.
Given the paths of the two dirs - dir1 and dir2,then dir2 should be synchronized with dir 1:
If a file exists in dir1 but not in dir2,it should be copied
-if a file exists in dir1 and in dir2,but content is changed,then file from dir1 should overwrite the one from dir2
-if a file exists in dir2 but not in dir1 it should be removed
Notes: files can be extremly large
-dir1 can have nested folders
hints:
-read and write files async
-hash files content and compare hashes not content
I have some logic on how to do this,but i dont know how to implement it.I googled the whole internet to get a point to start,but unsuccesseful.
I started with this:
using System.Security.Cryptography;
class Program
{
static void Main(string[] args)
{
string sourcePath = #"C:\Users\artio\Desktop\FASassignment\root\dir1";
string destinationPath = #"C:\Users\artio\Desktop\FASassignment\root\dir2";
string[] dirsInSourcePath = Directory.GetDirectories(sourcePath, "*", SearchOption.AllDirectories);
string[] dirsInDestinationPath = Directory.GetDirectories(destinationPath, "*", SearchOption.AllDirectories);
var filesInSourcePath = Directory.GetFiles(sourcePath, "*", SearchOption.AllDirectories);
var filesInDestinationPath = Directory.GetFiles(destinationPath,"*",SearchOption.AllDirectories);
//Directories in source Path
foreach (string dir in dirsInSourcePath)
{
Console.WriteLine("sourcePath:{0}", dir);
Directory.CreateDirectory(dir);
}
//Directories in destination path
foreach (string dir in dirsInDestinationPath)
{
Console.WriteLine("destinationPath:{0} ", dir);
}
//Files in source path
foreach (var file in filesInSourcePath)
{
Console.WriteLine(Path.GetFileName(file));
}
//Files in destination path
foreach (var file in filesInDestinationPath)
{
Console.WriteLine(Path.GetFileName(file));
}
}
}
As i understand,i should check if in dir1 are some folders and files,if true,copy them in folder 2,and so on,but how to do this? i'm burning my head out two days already and have no idea.. please help.
Edit: For the first and second point i got a solution. :
public static void CopyFolderContents(string sourceFolder, string destinationFolder, string mask, Boolean createFolders, Boolean recurseFolders)
{
try
{
/*if (!sourceFolder.EndsWith(#"\")) { sourceFolder += #"\"; }
if (!destinationFolder.EndsWith(#"\")) { destinationFolder += #"\"; }*/
var exDir = sourceFolder;
var dir = new DirectoryInfo(exDir);
SearchOption so = (recurseFolders ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
foreach (string sourceFile in Directory.GetFiles(dir.ToString(), mask, so))
{
FileInfo srcFile = new FileInfo(sourceFile);
string srcFileName = srcFile.Name;
// Create a destination that matches the source structure
FileInfo destFile = new FileInfo(destinationFolder + srcFile.FullName.Replace(sourceFolder, ""));
if (!Directory.Exists(destFile.DirectoryName) && createFolders)
{
Directory.CreateDirectory(destFile.DirectoryName);
}
if (srcFile.LastWriteTime > destFile.LastWriteTime || !destFile.Exists)
{
File.Copy(srcFile.FullName, destFile.FullName, true);
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message + Environment.NewLine + Environment.NewLine + ex.StackTrace);
}
}
It's not perfect,but it works.How this function should be improved: add async copy,and compare hashes of files not to copy again the identical ones. How to do it?
So,after some time of much more research,i came up with this solution:
using System.Diagnostics;
class Program
{
static void Main(string[] args)
{
string sourcePath = #"C:\Users\artio\Desktop\FASassignment\root\dir1";
string destinationPath = #"C:\Users\artio\Desktop\FASassignment\root\dir2";
var source = new DirectoryInfo(sourcePath);
var destination = new DirectoryInfo(destinationPath);
CopyFolderContents(sourcePath, destinationPath, "", true, true);
DeleteAll(source, destination);
}
public static void CopyFolderContents(string sourceFolder, string destinationFolder, string mask, Boolean createFolders, Boolean recurseFolders)
{
try
{
var exDir = sourceFolder;
var dir = new DirectoryInfo(exDir);
var destDir = new DirectoryInfo(destinationFolder);
SearchOption so = (recurseFolders ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
foreach (string sourceFile in Directory.GetFiles(dir.ToString(), mask, so))
{
FileInfo srcFile = new FileInfo(sourceFile);
string srcFileName = srcFile.Name;
// Create a destination that matches the source structure
FileInfo destFile = new FileInfo(destinationFolder + srcFile.FullName.Replace(sourceFolder, ""));
if (!Directory.Exists(destFile.DirectoryName) && createFolders)
{
Directory.CreateDirectory(destFile.DirectoryName);
}
//Check if src file was modified and modify the destination file
if (srcFile.LastWriteTime > destFile.LastWriteTime || !destFile.Exists)
{
File.Copy(srcFile.FullName, destFile.FullName, true);
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message + Environment.NewLine + Environment.NewLine + ex.StackTrace);
}
}
private static void DeleteAll(DirectoryInfo source, DirectoryInfo target)
{
if (!source.Exists)
{
target.Delete(true);
return;
}
// Delete each existing file in target directory not existing in the source directory.
foreach (FileInfo fi in target.GetFiles())
{
var sourceFile = Path.Combine(source.FullName, fi.Name);
if (!File.Exists(sourceFile)) //Source file doesn't exist, delete target file
{
fi.Delete();
}
}
// Delete non existing files in each subdirectory using recursion.
foreach (DirectoryInfo diTargetSubDir in target.GetDirectories())
{
DirectoryInfo nextSourceSubDir = new DirectoryInfo(Path.Combine(source.FullName, diTargetSubDir.Name));
DeleteAll(nextSourceSubDir, diTargetSubDir);
}
}
}
It does everything it should,the only missing points are the async copy and sha comparison,but at least i have a solution.
I have code that steps through a main directory and all the sub directories. The images in each sub directories needs to be renamed as per the folder it is ins name.
C:\Users\alle\Desktop\BillingCopy\uploaded 27-02\\Batch002-190227010418829\PPA14431564096\File1.png
should rename to
C:\Users\alle\Desktop\BillingCopy\uploaded 27-02\Batch002-190227010418829\PPA14431564096\PPA14431564096.png
I can see the code is stepping through every thing but the image isn't beeing renamed and I can't see where I went wrong
while(isTrue)
{
try
{
//write your code here
string filename1 = "1.tif";
string newFileName = "allen.tif";
string[] rootFolder = Directory.GetDirectories(#"C:\Users\alle\Desktop\BillingCopy");
foreach(string dir in rootFolder)
{
string[] subDir1 = Directory.GetDirectories(dir);
foreach(string subDir in subDir1)
{
string[] batchDirList = Directory.GetDirectories(subDir);
foreach(string batchDir in batchDirList)
{
string[] waybillNumberDir = Directory.GetDirectories(batchDir);
foreach(string hawbDir in waybillNumberDir)
{
string waybillNumber = Path.GetDirectoryName(hawbDir);
string[] getFileimages = Directory.GetFiles(hawbDir);
foreach(string imgInDir in getFileimages)
{
File.Copy(imgInDir, Path.Combine(#"C:\Users\alle\Desktop\Copy", string.Format("{0}.{1}", waybillNumber, Path.GetExtension(imgInDir))));
}
}
}
}
}
File.Copy(Path.Combine("source file", filename1), Path.Combine("dest path",
string.Format("{0}{1}", Path.GetFileNameWithoutExtension(newFileName), Path.GetExtension(newFileName))), true);
}
catch { }
}
When querying you can try using Linq to obtain the required data:
// All *.png files in all subdirectories
string rootDir = #"C:\Users\alle\Desktop\BillingCopy";
var agenda = Directory
.EnumerateFiles(rootDir, "*.png", SearchOption.AllDirectories)
.Select(file => new {
oldName = file,
newName = Path.Combine(
Path.GetDirectoryName(file),
new DirectoryInfo(Path.GetDirectoryName(file)).Name + Path.GetExtension(file))
})
.ToArray();
Then we can move (not copy) the files:
foreach (var item in agenda)
File.Move(item.oldName, item.newName);
i have put together this code which renames all the files in a folder in numeric order. What i want to do is make the last image have the name "1", 2nd to last image be named "2" if you catch my drift. im not sure how to do it. i have this so far
try
{
string Path = #"C:\Users\William\Pictures\Documents\Apple iPhone\";
DirectoryInfo di = new DirectoryInfo(Path);
FileInfo[] fiArr = di.GetFiles("*.jpg");
int i = 1;
string path;
foreach (FileInfo fri in fiArr)
{
path = Path + i.ToString() + ".jpg";
fri.MoveTo(path);
i++;
}
}
catch { }
Try this:
try
{
string Path = #"C:\Users\William\Pictures\Documents\Apple iPhone\";
DirectoryInfo di = new DirectoryInfo(Path);
FileInfo[] fiArr = di.GetFiles("*.jpg");
for (var i = fiArr.Length; i > 0; i--)
{
var fri = fiArr[i - 1];
var path = Path + i.ToString() + ".jpg";
fri.MoveTo(path);
}
}
catch { }
I tried to copy everything in an folder to an other folder, but i try to Not Create a subfolder in the targetpath instead i try to take the name of the subfolder in the sourcepath and add it infront of the tagetpath and set a underscore betwen them
Exaple:
sourcefolder
├file1.txt
├subfolder1
|└file2.txt
└subfolder2
├subfolder3
|└file3.txt
└subfolder4
└file4.txt
Gets to:
targetfolder:
├file1.txt
├subfolder1_file2.txt
├subfolder2_subfolder3_file3.txt
├subfolder2_subfolder4_file4.txt
Currently i just get it with folders:
foreach (string dirPath in Directory.GetDirectories(sourcePath, "*", SearchOption.AllDirectories))
{
Directory.CreateDirectory(dirPath.Replace(sourcePath, targetPath));
}
foreach (string srcPath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories))
{
newPath = srcPath.Replace(sourcePath, targetPath);
File.Copy(srcPath, newPath, true);
}
And i tried it with :
private void showDeletefiles(string filePath)
{
string[] installfiles = Directory.GetFiles(Path.GetDirectoryName(filePath));
string[] subfolders = Directory.GetDirectories(Path.GetDirectoryName(filePath));
string appdatafolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
int i = 0;
foreach (string file in installfiles)
{
string fileName = Path.GetFileName(file);
string fileextension = Path.GetExtension(fileName);
if (!File.Exists(sourcefoldervalueLabel + file) && fileextension != ".manifest")
{
File.Copy(filePath + fileName, appdatafolder+ fileName, true);
}
if (subfolders.Length >= 0)
{
string[] subfolderfiles = Directory.GetFiles(subfolders[i]);
string foldername = Path.GetFileName(subfolders[i]);
i++;
foreach (string subfiles in subfolderfiles)
{
File.Copy(filePath + fileName, appdatafolder + foldername + "_" + subfiles, true);
}
}
}
}
The problem is i go only into the first "subfolder"
You can generate a FileInfo object from each of your strings and extract the proper information from there. This should work, assuming you have a path of "DirectoryLetter:\Folder\Files" or "DirectoryLetter:\Files". Note this is obviously not the most efficient code with the use of string.Replace and of course this will have to be tested with all your common scenarios.
var fileInfos = Directory.GetFiles(#"DirectoryToTraverseHere", "*.*", SearchOption.AllDirectories)
.Select(file => new FileInfo(file));
foreach (var fileInfo in fileInfos)
{
string newFileInfo;
if (fileInfo.Directory.Parent.Name == fileInfo.Directory.Root.Name)
{
newFileInfo = string.Format("{0}_{1}", fileInfo.Directory.FullName, fileInfo.Name);
}
else
{
newFileInfo = string.Format("{0}_{1}{2}", fileInfo.Directory.Parent.FullName,
fileInfo.Directory.Name,
fileInfo.Name);
}
File.Copy(fileInfo.FullName, Path.Combine("TargetDirectory", newFileName));
}
I solved my Question by myself:
The Code:
string[] installfiles = Directory.GetFiles(Path.GetDirectoryName(filePath));
string[] subfolders = Directory.GetDirectories(Path.GetDirectoryName(filePath));
string appdatafolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
int i = 0;
foreach (string file in installfiles)
{
string fileName = Path.GetFileName(file);
string fileextension = Path.GetExtension(fileName);
if (!Directory.Exists(appdatafolder))
{
Directory.CreateDirectory(appdatafolder);
}
File.Copy(filePath + fileName, appdatafolder + fileName, true);
if (subfolders.Length >= 0 && i < subfolders.Length)
{
string[] subfolderfiles = Directory.GetFiles(subfolders[i]);
string foldername = Path.GetFileName(subfolders[i]);
i++;
foreach (string subfiles in subfolderfiles)
{
string subfilesname = Path.GetFileName(subfiles);
File.Copy(filePath + fileName, appdatafolder + foldername + "_" + subfilesname, true);
}
}
}
This is how i needed it hopefully it helps you out :)
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)));
}
}
}
}