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);
}
}