在C#/.NET中同步两个目录(从源目录更新目标目录)
我想同步两个目录,这样在操作之后,目标目录就是源目录的精确副本。将新的源文件/子目录添加到目标中,较新的源文件将替换较旧的目标版本,源中缺少的文件将从目标中删除 我知道我可以递归地遍历这两棵树,检查是否存在,并比较上次写入日期 我的问题:是否有现成的东西可以用来代替编写自己的代码?类似于在C#/.NET中同步两个目录(从源目录更新目标目录),c#,.net,C#,.net,我想同步两个目录,这样在操作之后,目标目录就是源目录的精确副本。将新的源文件/子目录添加到目标中,较新的源文件将替换较旧的目标版本,源中缺少的文件将从目标中删除 我知道我可以递归地遍历这两棵树,检查是否存在,并比较上次写入日期 我的问题:是否有现成的东西可以用来代替编写自己的代码?类似于TargetDir.UpdateFromSourceDir(SourceDir)的东西:-) 我在这里找到了带有DirectorySynchronization类的System.DirectoryServices
TargetDir.UpdateFromSourceDir(SourceDir)的东西代码>:-)
我在这里找到了带有DirectorySynchronization类的System.DirectoryServices:。从它的名字来看,它似乎可以做我想做的事情,但从它的方法来看,我对此表示怀疑。在我将展示的示例中,有很多方法可以做到这一点
- 最简单的方法是使用同步库
- 否则,将删除并复制目录
- 如果您不想这样做,最安全的方法(尽管容易发生更多的数据竞争)是散列所有文件,列出要删除、添加和更新的文件列表
- 最不安全的方法是执行上述操作,但使用文件日期
就个人而言,我只是删除和复制,然后转到其他内容,不过你可以试试这个
预警:如果可以找到同步库,请使用同步库。这纯粹是出于学术目的,并不等同于世界上最好的解决方案
给定的
public static (HashSet<string> dirs, HashSet<(string file,long tick)> files) Get(string dir)
{
string CleanPath(string path) => path.Substring(dir.Length).TrimStart('/', '\\');
// replace this with a hashing method if you need
long GetUnique(string path) => new FileInfo(path).LastWriteTime.Ticks;
var directories = Directory.GetDirectories(dir, "*.*", SearchOption.AllDirectories);
var dirHash = directories.Select(CleanPath).ToHashSet();
// this could be paralleled if need be (if using a hash)
var fileHash = directories.SelectMany(Directory.EnumerateFiles)
.Select(file => (name: CleanPath(file), ticks : GetUnique(file)))
.ToHashSet();
return (dirHash, fileHash);
}
注意:失败的方法有很多,假设您有权限这样做,并且文件没有被锁定。这还应该有大量的错误检查,可能需要定制,并且在使用它之前,您应该进行大量的尽职调查(请注意)建议使用Microsoft Sync Framework。我通过NuGet获得了Microsoft.SyncFramework的。我认为这意味着这个库基于另一个不再存在的库
由于我的程序只能在Windows下运行,我在这里找到了一个简单的解决方案:。其想法是运行Windows附带的命令行工具robocopy.exe,并完全执行我想要的操作(使用选项/MIR)
这回答了你的问题吗@查理脸:谢谢。这个看起来不错,不过我不知道怎么用。他们提到了FileSyncProvider和SyncOrchestrator,但没有说明要包括哪些程序集以及需要使用什么using指令。“你能解释一下吗?”汉斯·帕桑:谢谢。这似乎只是用蛮力(不检查目标文件是否为当前文件)覆盖所有源文件的所有目标文件,我不认为当源文件中不再存在文件时会从目标文件中删除这些文件。要做到这一点,最简单的方法是删除并复制目录。如果您不想这样做,最安全的方法(尽管容易发生更多的数据竞争)是散列所有文件,列出要删除、添加和更新的文件列表。最不安全的方法是执行上述操作,但使用上次修改的日期和时间。就我个人而言,我只是删除和复制,并转移到其他东西上,谢谢你为此付出了这么多的努力。我找不到同步库。我想推荐的Microsoft库已经不存在了。我喜欢你的方法,从中我学到了很多。非常感谢。
var result1 = Get(dir1);
var result2 = Get(dir2);
var dirsToRemove = result2.dirs.Where(x => !result1.dirs.Contains(x));
var filesToRemove = result2.files.Where(x => !result1.files.Contains(x));
var filesToAdd = result1.files.Where(x => !result2.files.Contains(x));
foreach (var fileToRemove in filesToRemove)
Console.WriteLine("Deleting : " + Path.Combine(dir2, fileToRemove.file));
foreach (var dirToRemove in dirsToRemove)
Console.WriteLine("Deleting : " + Path.Combine(dir2, dirToRemove));
foreach (var fileToAdd in filesToAdd)
Console.WriteLine("Adding : " + Path.Combine(dir2,fileToAdd.file));
using (Process RoboCopyProcess = new Process())
{
RoboCopyProcess.StartInfo.FileName = "robocopy.exe";
RoboCopyProcess.StartInfo.Arguments = SourceDirPath + " " + TargetDirPath + " /MIR";
RoboCopyProcess.StartInfo.UseShellExecute = false;
RoboCopyProcess.StartInfo.CreateNoWindow = true;
RoboCopyProcess.Start();
RoboCopyProcess.WaitForExit();
}