This program moves files to a backup directory, archiving them by year of last modification.
From a directory like :
. ├── file1.ext ├── file2.ext ├── file3.ext ├── fileN.ext To destination:
. ├── _Backup | ├── 2002 | └──_200X | ├── file3.ext | └── fileN.ext ├── file1.ext ├── file2.ext Configuration.xml:
<?xml version="1.0" encoding="utf-8" ?> <data> <PathItem PathFrom="C:\Test\FjournaTest" PathTo ="C:\Test\FjournaTest\bak" Delay="20" Enable="1" /> <PathItem PathFrom="\\AAAAAAA\BBB\Commun\Email\XYZ\" PathTo ="\\AAAAAAA\BBB\Commun\Email\XYZ\Backup" Delay="30" Enable="0" /> </data> Delay is the number of days old the file needs to be eligible to the backup.
FileMover.Cs
class FileMove { private IEnumerable<PathItem> _pathList; private bool _Talk = false; private DateTime currentDate = DateTime.Now; private int tryMAX = 7; public FileMove(string configPath) { if (!PathValid(configPath)) { throw new Exception($"Invalid Configuration Path: [{configPath}]."); } XDocument doc = XDocument.Load(configPath); var tempP = from p in doc.Descendants("PathItem") where int.Parse(p.Attributes("Enable").First().Value) == 1 select new PathItem( p.Attributes("PathFrom").First().Value , p.Attributes("PathTo").First().Value , int.Parse(p.Attributes("Delay").First().Value) , true ); //Distinct on From. _pathList = tempP.GroupBy( i => i.PathFrom, (key, group) => group.First() ).ToArray(); } public FileMove(string configPath, bool talk) : this(configPath) { this._Talk = talk; } public void Run() { if (!_pathList.Any()) { W("No Enabled Path."); return; } I("Process Start."); foreach (var x in _pathList) { I($"Processing:\n{x}");//TODO Try > Catch > Log. Process(x.PathFrom, x.PathTo, x.Delay); } I("Process End."); } private void Process(string pathFrom, string pathTo, int delay) { bool ValidPathFrom = PathValid(pathFrom) , ValidPathTo = PathValid(pathTo); if (!(ValidPathFrom && ValidPathTo)) { W("Path Not Valid!"); W($"\tPathFrom:{ValidPathFrom}\tPathTo:{ValidPathTo}"); return; } I($"\tPath Valid >PathFrom:{pathFrom}\t>PathTo:{pathTo}"); string[] fileEntries = Directory.GetFiles(pathFrom); Parallel.ForEach(fileEntries, (fileName) => { ProcessFile(fileName, pathTo, delay); }); } private void ProcessFile(string fileName, string pathTo, int delay) { var fileInfo = new FileInfo(fileName); DateTime lastModified = fileInfo.LastWriteTime; int DuplicateCounter = 0; var yearDirectory = lastModified.Year.ToString(); string shortName = Path.GetFileNameWithoutExtension(fileInfo.Name); pathTo += $"\\{yearDirectory}"; string savePath = $"{pathTo}\\{fileInfo.Name}"; if (delay == 0 || (currentDate - lastModified).Days >= delay) { //Year Dir Exist ? if (!PathValid(pathTo)) { Directory.CreateDirectory(pathTo); } // Make sure that the target does not exist. while (File.Exists(savePath) && DuplicateCounter < 99) { DuplicateCounter++; savePath = $"{pathTo}\\{shortName}({DuplicateCounter}){fileInfo.Extension}"; if (DuplicateCounter == 99) { W($"\t\t[{shortName}] Have to many duplicate."); } } // MoveIt. int tryCount = 0; while (tryCount < tryMAX + 1) { try { fileInfo.MoveTo(savePath); } catch (Exception e) { if (tryCount == tryMAX) {//thinks 7 time before it speaks throw new Exception($"-File move : {savePath} #Failed", e); } tryCount++; continue; } break; } I("{0} was moved to {1}.", fileName, savePath); } } private bool PathValid(string path) { if (File.Exists(path)) { return true; } else if (Directory.Exists(path)) { return true; } else { W("{0} is not a valid directory or file.", path); return false; } } private bool PathValid(string path, out bool validPathFrom) { validPathFrom = PathValid(path); return validPathFrom; } public void W(string format, params object[] args) //Warning always printed { #if DEBUG System.Diagnostics.Debug.WriteLine(format, args); #endif Console.WriteLine(format, args); } public void I(string format, params object[] args) //InfoCut off if not talkative. { if (_Talk) W(format, args); } }