我喜欢这个主意,所以我自己尝试了这个。结果比我想象的要复杂一些。让我们深入了解一下,好吗?
基本思想是同步目录,所以我们想要引用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()
- 我们永远不能假设只有一个人/进程在目录中工作。
SynchronizeFiles
做两件事:
- 将当前目录中的所有文件复制/覆盖到目标目录中。
- 删除源目录中不再存在的冗余文件
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
,它可以递归地检测所选目录中的所有更改。