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.
In C# while moving files from source to destination folders, how to rename the destination file with prefix of directory name to each file?
static void Main(string[] args)
{
string sourceFolder = #"C:\Source";
string destinationFolder = #"C:\Destination\";
string dirName = Path.Combine(destinationFolder, DateTime.Now.ToString("dd-MM-yyyy"));
Directory.CreateDirectory(dirName);
DirectoryInfo di = new DirectoryInfo(sourceFolder);
string searchXlsPattern = "*.xls*";
try
{
//Getting list of files from Nested sub folders
ICollection<FileInfo> files = di.GetFiles(searchXlsPattern, SearchOption.AllDirectories).Where(file => !file.DirectoryName.Contains("Archive"))
.Select(x => x)
.ToList();
if (files != null && files.Count() > 0)
{
foreach (FileInfo currentfile in files)
{
if (new FileInfo(dirName + "\\" + currentfile.Name).Exists == false)
{
//Renaming old file name to new file Name
string fileDirectoryName = "";
fileDirectoryName = Path.GetDirectoryName(currentfile.FullName);
string replaceSlash = Convert.ToString(fileDirectoryName.Replace("\\", "_"));
string replaceSplChar= replaceSlash.Replace(":", "_");
string fileextension = Path.GetExtension(currentfile.Name);
string fname = currentfile.Name.Replace(fileextension, "");
string newFileName = replaceSplChar.ToString()+ "_" + fname + fileextension;
//Copy the file to destination folder
//tempfile.CopyTo(Path.Combine(destinationFolder, newFileName), true);
//Move the file to destination folder
currentfile.MoveTo(dirName + "\\" + newFileName);
////File.Move(currentfile.DirectoryName + "\\" + currentfile.Name, dirName + "\\" + newFileName);
//File.Move(currentfile.DirectoryName + "\\" + currentfile.Name, dirName + "\\" + newFileName);
}
}
}
else
Console.Write("There is no files in Source");
}
catch (IOException Exception)
{
Console.Write(Exception);
}
}
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 little problem with converting, I try to convert folder where is subfolders but its not creating subfolders, makes only one folder "_converted" and in the folder is all converted subfolder images.
My code:
private void btnConvert_Click(object sender, EventArgs e)
{
string[] originalImage = Directory.GetDirectories(txtFilePath.Text, "*.*",
SearchOption.AllDirectories);
foreach (var directory in originalImage)
{
Debug.WriteLine(directory);
}
foreach (string dir in originalImage)
{
string folderPath = #"C:\test\" + "_converted";
folderPath = folderPath.Substring(folderPath.IndexOf(#"\") + 1);
DirectoryInfo di = Directory.CreateDirectory(folderPath);
if (Directory.Exists(folderPath))
{
DirectoryInfo dInfo = new DirectoryInfo(dir);
foreach (var filename in dInfo.GetFiles())
{
FileInfo fInfo = new FileInfo(filename.FullName);
var fileExtension = fInfo.Extension;
var fileOriginalDate = fInfo.CreationTime;
if (fileExtension.ToUpper() == ".JPG" || fileExtension.ToUpper() == ".PNG")
{
using (Bitmap bitmap = new Bitmap(filename.FullName))
{
string fn = Path.GetFileNameWithoutExtension(filename.FullName);
VariousQuality(bitmap, fn, fileExtension,
fileOriginalDate, folderPath);
}
}
}
}
}
}
I tried to use this method:
folderPath = folderPath.Substring(folderPath.IndexOf(#"\") + 1);
How I can resolve this problem?
You are not handling the folders' names correctly. Try this:
private void btnConvert_Click(object sender, EventArgs e)
{
string[] originalImage = Directory.GetDirectories(txtFilePath.Text, "*.*", SearchOption.AllDirectories);
foreach (var directory in originalImage)
{
Debug.WriteLine(directory);
}
foreach (string dir in originalImage)
{
// The name of the current folder (dir)
// This will convert "C:\Users\User\Desktop\Myfolder\Image1" to simply "Image1" since we create a substring after the LAST backslash ('\')
string folderName = dir.Substring(dir.LastIndexOf('\\') + 1); // Ex. "Image1"
// This will now be "C:\test\FOLDERNAME_converted"
string folderPath = #"C:\test\" + folderName + #"_converted\"; // Ex. "C:\test\image1_converted\";
// This can now create the folders
DirectoryInfo di = Directory.CreateDirectory(folderPath);
// Below is unchanged for now
if (Directory.Exists(folderPath))
{
DirectoryInfo dInfo = new DirectoryInfo(dir);
foreach (var filename in dInfo.GetFiles())
{
FileInfo fInfo = new FileInfo(filename.FullName);
var fileExtension = fInfo.Extension;
var fileOriginalDate = fInfo.CreationTime;
if (fileExtension.ToUpper() == ".JPG" || fileExtension.ToUpper() == ".PNG")
{
using (Bitmap bitmap = new Bitmap(filename.FullName))
{
string fn = Path.GetFileNameWithoutExtension(filename.FullName);
VariousQuality(bitmap, fn, fileExtension,
fileOriginalDate, folderPath);
}
}
}
}
}
}
I Hope this helps.
I just have one question. When getting the directories in your directory path (txtFilePath.Text), you get all folders including subfolders (SearchOptions.AllDirectories). When saving the converted folders to the "C:\test" folder, you don't take into account that a folder could have been a subfolder. Because of this the following problem happens. Let's say you have a folder with a folder with a folder:
"HeadFolder -> Image1 -> Image1.2"
What the program will find:
1. "Path\\To\\Image1"
2. "Path\\To\\Image1.2"
After converting you'll get:
"HeadFolder"
"Image1"
"Image1.2"
Notice that "Image1.2" does NOT end up inside "Image1" as prior to conversion
You're creating the same folder in each iteration of the loop. Just create a folder using the current directory by replacing the below lines:
string folderPath = #"C:\test\" + "_converted";
folderPath = folderPath.Substring(folderPath.IndexOf(#"\") + 1);
With this line:
string folderPath = Path.Combine(#"C:\test\", dir + "_converted");
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)));
}
}
}
}