Sync.cs
Synchronize Files of two folder / subdirectoriesunknown
csharp
4 years ago
5.5 kB
20
Indexable
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
namespace FileTools
{
public struct Command
{
public enum Kind
{
Missing,
Ecxess,
DateMismatch
}
public Kind Type { get; }
public IDirectoryInfo Source { get; }
public IDirectoryInfo Destination { get; }
public string FileLocation { get; }
public Command(Kind syncCommandKind, IDirectoryInfo source, IDirectoryInfo destination, string fileLocation)
{
if (string.IsNullOrEmpty(fileLocation))
throw new ArgumentException($"'{nameof(fileLocation)}' cannot be null or empty.", nameof(fileLocation));
Type = syncCommandKind;
Source = source;
Destination = destination;
FileLocation = fileLocation;
}
}
public delegate void InterpretCommandDelegate(Command command);
public static class DirectorySynchronizer
{
private static IEnumerable<string> GetRelativeFiles(IDirectoryInfo dI, string fP, SearchOption sO) =>
dI.GetFiles(fP, sO).Select(f => Path.GetRelativePath(dI.FullName, f.FullName));
private static string RootFile(IDirectoryInfo root, string fileLocation) =>
Path.Combine(root.FullName, fileLocation);
public static IEnumerable<Command> QueryCommands(IFileSystem fileSystem, IDirectoryInfo source, IDirectoryInfo destination, string filePattern, SearchOption searchOption)
{
var sourceFiles = GetRelativeFiles(source, filePattern, searchOption);
var destinationFiles = GetRelativeFiles(destination, filePattern, searchOption);
var filesPresentInBothLocations = sourceFiles.Intersect(destinationFiles);
var missingFiles = sourceFiles.Except(filesPresentInBothLocations);
var excessFiles = destinationFiles.Except(filesPresentInBothLocations);
var filesPresentInBothLocationsWithDifferentDate =
filesPresentInBothLocations
.Where(f => fileSystem.FileInfo.FromFileName(RootFile(source, f)).LastWriteTime != fileSystem.FileInfo.FromFileName(RootFile(destination, f)).LastWriteTime);
return missingFiles
.Select(mf => new Command(Command.Kind.Missing, source, destination, mf))
.Concat(excessFiles.Select(ef => new Command(Command.Kind.Ecxess, source, destination, ef)))
.Concat(filesPresentInBothLocationsWithDifferentDate.Select(dMF => new Command(Command.Kind.DateMismatch, source, destination, dMF)));
}
public static void InterpretCommand(IFileSystem fileSystem, Command command)
{
switch(command)
{
case Command { Type: Command.Kind.Missing }:
{
var sourceFileLocation = RootFile(command.Source, command.FileLocation);
var destinationFileLocation = RootFile(command.Destination, command.FileLocation);
var destinationDirectoryLocation = fileSystem.Path.GetDirectoryName(destinationFileLocation);
// Create directory if not present, so files can be copied
if (fileSystem.Directory.Exists(destinationDirectoryLocation) == false)
fileSystem.Directory.CreateDirectory(destinationDirectoryLocation);
fileSystem.File.Copy(sourceFileLocation, destinationFileLocation);
} break;
case Command { Type: Command.Kind.Ecxess }:
{
fileSystem.File.Delete(RootFile(command.Destination, command.FileLocation));
} break;
case Command { Type: Command.Kind.DateMismatch }:
{
var sourceFileLocation = RootFile(command.Source, command.FileLocation);
var destinationFileLocation = RootFile(command.Destination, command.FileLocation);
fileSystem.File.Copy(sourceFileLocation, destinationFileLocation, true);
} break;
default: throw new ArgumentOutOfRangeException("command.Kind");
}
}
public static InterpretCommandDelegate CreateCommandInterpreter(IFileSystem fileSystem) =>
delegate (Command command) { InterpretCommand(fileSystem, command); };
public static void InterpretCommands(InterpretCommandDelegate commandInterpreter, IEnumerable<Command> commands)
{
foreach (var command in commands)
commandInterpreter(command);
}
public static void Synchronize(IFileSystem fileSystem, IDirectoryInfo source, IDirectoryInfo destination, string filePattern, SearchOption searchOption) =>
InterpretCommands(CreateCommandInterpreter(fileSystem), QueryCommands(fileSystem, source, destination, filePattern, searchOption));
public static void Synchronize(IFileSystem fileSystem, IDirectoryInfo source, IDirectoryInfo destination, string filePattern, SearchOption searchOption, InterpretCommandDelegate command) =>
InterpretCommands(CreateCommandInterpreter(fileSystem) + command, QueryCommands(fileSystem, source, destination, filePattern, searchOption));
}
}
Editor is loading...