アイデアが気に入ったので、自分で試してみました。思ったよりも少し複雑であることがわかりました。深く掘り下げましょう、いいですか?
基本的な考え方はディレクトリを同期することなので、DirectoryInfo
インスタンスへの参照が必要です。
var source = new DirectoryInfo(@"C:\SynchSource");
var target = new DirectoryInfo(@"C:\SynchTarget");
Synchronize(source, target);
Synchronize
ほとんどの場合、次の方法で機能します。
- すべてのファイルが同一であることを確認してください
- すべてのディレクトリが同一であることを確認してください
- すべてのサブディレクトリを通過してトラバースする
私の実装は次のようになります。
void Synchronize(DirectoryInfo sourceDir, DirectoryInfo targetDir)
{
SynchronizeFiles(sourceDir, targetDir);
SynchronizeDirectories(sourceDir, targetDir);
TraverseDirectories(sourceDir, targetDir);
}
注意してください.Single()
- ディレクトリ内で作業している人物/プロセスが 1 つだけであるとは決して想定できません。
SynchronizeFiles
次の 2 つのことを行います。
- 現在のディレクトリ内のすべてのファイルをターゲット ディレクトリにコピー/上書きします。
- ソースディレクトリに存在しなくなった冗長ファイルを削除します
void MoveFiles(DirectoryInfo sourceDir, DirectoryInfo targetDir)
{
foreach (FileInfo sourceFile in sourceDir.GetFiles())
{
string targetFilePath = Path.Combine(targetDir.FullName, sourceFile.Name);
File.Copy(sourceFile.FullName, targetFilePath);
}
}
void RemoveRedundantFiles(DirectoryInfo sourceDir, DirectoryInfo targetDir)
{
foreach (var targetFile in targetDir.GetFiles())
{
var sourceFilePath = Path.Combine(sourceDir.FullName, targetFile.Name);
if (!File.Exists(sourceFilePath))
{
targetFile.Delete();
}
}
}
これで、現在のディレクトリ内のすべてのファイルが同じであり、それ以上でもそれ以下でもないと仮定できます。サブディレクトリをトラバースするには、まずディレクトリ構造が同じであることを確認する必要があります。と同様の方法でそれを行いますSynchronizeFiles
:
- 不足しているディレクトリをターゲット ディレクトリに作成する (
CreateMissingDirectories
)
- ソース ディレクトリに存在しない冗長なディレクトリを削除します (
RemoveRedundantDirectories
)
void CreateMissingDirectories(DirectoryInfo sourceDir, DirectoryInfo targetDir)
{
foreach (DirectoryInfo sourceSubDir in sourceDir.GetDirectories())
{
string targetSubDirPath = Path.Combine(targetDir.FullName, sourceSubDir.Name);
if (!Directory.Exists(targetSubDirPath))
{
Directory.CreateDirectory(targetSubDirPath);
}
}
}
void RemoveRedundantDirectories(DirectoryInfo sourceDir, DirectoryInfo targetDir)
{
foreach (DirectoryInfo targetSubDir in targetDir.GetDirectories())
{
string sourceSubDirPath = Path.Combine(sourceDir.FullName, targetSubDir.Name);
if (!Directory.Exists(sourceSubDirPath))
{
targetSubDir.Delete(true);
}
}
}
現在の階層レベルのファイルとディレクトリが等しい状態です。すべてのサブディレクトリを繰り返し処理して、Synchronize を呼び出すことができます。
void TraverseDirectories(DirectoryInfo sourceDir, DirectoryInfo targetDir)
{
foreach (DirectoryInfo sourceSubDir in sourceDir.GetDirectories())
{
DirectoryInfo targetSubDir = targetDir.GetDirectories(sourceSubDir.Name).Single();
Synchronize(sourceSubDir, targetSubDir);
}
}
これで完了です。
巨大なディレクトリ階層、大量または大きなファイル、さらにはディレクトリ内で動作する同時プロセスについては、改善の余地がたくさんあります。GetFiles
高速にするためにやるべきことはたくさんあります ( /をキャッシュしたいかもしれませんGetDirectories
)、不要な呼び出しをスキップFile.Copy
します (コピーが必要であると仮定する前にファイル ハッシュを取得します)。
補足として: ファイルを時々同期する以外に、要件に応じてFileSystemWatcher
、選択したディレクトリ内のすべての変更を再帰的に検出できる を参照することをお勧めします。