65.9K
CodeProject 正在变化。 阅读更多。
Home

目录镜像应有的工作方式

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.89/5 (12投票s)

2009年6月9日

CPOL

26分钟阅读

viewsIcon

50450

downloadIcon

1930

快速轻松地创建有用的目录还原点。

目录

引言

DirMirror在目标目录中创建并维护源目录的精确副本,为您选择的目录创建并维护“还原点”。目标目录中的文件和目录将与源目录中的文件和目录具有完全相同的日期和支持的属性。镜像过程将只复制与源中不同的目录和文件。目标中不存在于源中的文件和目录将被删除。“镜像”的精确性可以修改,以排除和/或忽略目录和文件,以保护目标中不应更改或删除的项目,并减少目标中复制时间和空间的使用。DirMirror适用于所有使用NTFS或FAT32文件系统的本地连接目录(硬盘、USB闪存盘、映射驱动器、网络共享等)。我已经在声称使用FAT文件系统的旧USB闪存盘上测试过它,但是,我不声称它适用于真实的FAT文件系统。DirMirror不支持FTP。要使用DirMirror,您必须根据其运行或访问的系统的规则具有适当的权限。

背景

除了正常的备份,我还喜欢在另一个磁盘上保留特定目录的精确副本。这个副本可以被认为是目录的还原点。它对于回答“发生了什么变化”这个问题特别有用。我还使用这种技术来协调桌面/笔记本电脑/其他系统情况下的活动目录。几年来,我一直为此目的使用SyncToy 1.4版,以“Echo”模式运行。最近,我尝试了SyncToy 2.0。它在“Echo”模式下是一场灾难。此外,在排查各种问题时,我注意到1.4版也并非完美无缺,尽管它的问题更细微、不那么重要。

既然我希望拥有镜像功能,并且不想处理寻找和测试其他替代包的问题,我问了一个问题:“自己编写一个有多难?”。结果,答案是“取决于你想要把它做得多难”。对于那些只想使用该软件包的人,所有代码细节都在DirMirror的工作原理部分中,可以跳过。对于我预期的读者,细节才是有趣的部分。

与Vista的同步中心相比

  • 同一台计算机上从源到目标的简单单向同步
  • 在XP和Vista上运行
  • 源和/或目标可以在网络文件夹上 - 与Vista Home...系统不同
  • 不需要服务或其他长时间运行的后台进程
  • 没有目录或数据库与现实脱节
  • 您控制它何时以及如何运行
  • 不声称适用于手机、MP3播放器等。

免责声明

DirMirror不是一个备份解决方案。对于备份,请使用声称用于此目的的软件包。DirMirror是一种为目录创建和维护还原点的方法,易于使用,速度取决于硬件(和Windows)所允许的速度,并且在我目前可用的测试硬件条件下,尽可能可靠。我不会在没有亲自测试的情况下使用别人的软件来做这样的事情。我也不期望CodeProject的成员会跳过测试阶段。

DirMirror不是一个同步解决方案。对于同步,请使用声称用于此目的的软件包。DirMirror使目标目录看起来与源目录完全相同。如果您在源和目标中都进行了更改,您将丢失对目标所做的更改,除非您明确忽略目标中这些更改的目录和文件。当然,您可以定义文件夹对,使源和目标反转,并使用它们进行同步,完全控制“同步”什么以及何时同步。在许多情况下(例如,一个人,两台计算机),对于那些喜欢保留对自己数据控制的人来说,这是一种更优选的方法。有关更多观点,请参阅本文后面我对备份、同步和镜像的定义

本文中使用的术语定义

在整个文章和代码中,文件由FileItem表示。目录由DirectoryItem表示。术语Item用于指代这两者中的任何一个实例。

在整个文章和代码中,术语Key指的是Item路径中去除源或目标路径后剩余的部分。这种去除使得末尾的Path.DirectorySeparatorChar成为Key的第一个字符。例如:给定源目录“C:\Test”,目录“C:\Test\Junk”的Key是“\Junk”,而“C:\Test”的Key是“\”。这个定义对于理解代码和应用于目录的模式匹配概念至关重要。

使用DirMirror

应用程序的每个用户都有一个FolderPair列表实例。每个FolderPair项指定一个源目录和一个目标目录。每个FolderPair还包含OptionIgnoreListExcludeList。这些列表允许用户在删除和复制操作中忽略和/或排除某些文件和目录。

DirMirror提供交互式GUI版本(DirMirror.exe)和命令行版本(DirMirror.com)。命令行版本将在后面讨论。GUI版本必须用于定义源和目标目录对,并设置FolderPair的任何选项。一旦FolderPair被定义和配置,它将可供所有未来的DirMirror执行使用,直到它被明确删除。

使用 DirMirror

  1. 启动DirMirror。
  2. 如果需要,通过点击“Create New FolderPair”创建所需的FolderPair。使用纯镜像的默认选项,或根据需要更改它们。
  3. 单击GUI左侧窗格中的FolderPair名称。这将更改显示并运行预览。
  4. 单击“Details”按钮查看待处理操作的另一个视图,如果需要,取消所选目录和文件上的操作(可选步骤)。
  5. 单击“Execute”按钮开始镜像操作。
  6. 观察发生了什么(可选步骤)。
  7. 根据需要重复。
  8. 退出DirMirror。

使用注意事项

GUI中的文本以两种蓝色色调显示。颜色较深的文本可以单击以触发某些操作。某些此类区域响应右键和左键单击,但有些只响应左键单击。例如,左键单击FolderPair名称将启动源和目标的扫描,并显示该FolderPair的预览/操作页面。右键单击FolderPair名称将允许您更改该对的选项,或删除FolderPair(仅删除DirMirror列表中的条目,而不是实际的目录),重命名一对,或以更方便的视图查看该对的选项。单击列表视图中任何深蓝色数字将显示属于该类别的目录或文件(例如,要删除的目录)。在Options设置分组框内的任何单击都将显示一个属性网格,允许您更改该对的任何选项。

演示下载中提供的 Demo_ReadMe.htm 提供了一个 GlobalFileIgnore 列表,该列表与通常只在其原始目录上下文中具有意义的文件匹配。您可以考虑将该列表用于所有 FolderPair

某些不常见的文件类型在从 NTFS 文件系统复制到远程或非 NTFS 文件系统时可能会导致错误并被跳过。我尚未在稀疏文件或具有重解析点的文件上测试过 DirMirror。如果您有此类文件并且可以测试 DirMirror,请执行此操作并告知我结果。

加密和压缩目录及文件

由NTFS加密或压缩的文件和目录不能很好地传输。这些限制仅适用于NTFS加密/压缩,不包括通过其他方法(WinZip等)完成的加密/压缩。此版本的DirMirror在将文件复制到与源位于同一系统上的固定驱动器NTFS卷上的目标时,保留文件的加密性质。当目录复制到与源位于同一系统上的固定驱动器NTFS卷上的目标时,它也将保留目录的“加密”属性。为了避免暴露其加密内容,加密文件不会复制到除同一系统上的固定驱动器NTFS卷之外的任何位置。

DirMirror 复制的压缩项在复制到固定驱动器 NTFS 卷时将保持压缩状态。压缩目录在复制到固定驱动器 NTFS 卷时保留“压缩”属性。复制到任何非固定驱动器 NTFS 卷的压缩项将以解压缩状态复制,并且不会保留压缩属性。

选项、排除列表和忽略列表

关于选项和列表,首先要知道的是,您应该有充分的理由使用它们。其次要知道的是,您必须阅读并理解本节。如果您不理解选项和列表之间的相互作用,并且没有完全掌握列表的工作原理,可能会得到奇怪且意想不到的结果。当然,您可以使用不带任何排除或忽略列表的“纯”镜像,因此不需要以下任何信息。

选项

覆盖 如何处理目标中较新文件的覆盖。选项是“Ask”、“Never”和“Always”,含义显而易见。
删除排除项 如何处理目标中与ExcludeList中的条目匹配的文件或目录。True表示删除,False表示不删除。
使用全局排除项 True 表示同时使用 Global ExcludeLists 和 FolderPair 唯一的 ExcludeLists。
使用全局忽略 True 表示同时使用 Global IgnoreLists 和 FolderPair 唯一的 IgnoreLists。

排除和忽略列表

忽略列表和排除列表是您希望以特殊方式处理的目录和文件列表。这些列表可以包含通配符。与列表中给定模式匹配的项将被“忽略”或“排除”。有四个全局列表(DirIgnoreDirExcludeFileIgnoreFileExclude)和四个FolderPair特定列表。全局列表与应用程序的用户相关联,而FolderPair特定列表对于特定的FolderPair是唯一的。FolderPair可以配置为使用所有、部分或不使用这些列表。

通配符和模式匹配

DirMirror使用VB.NET的Like运算符执行匹配。一个“*”字符将匹配任何字符的零个或多个出现。一个“?”字符将匹配任何单个字符。有关其他模式匹配功能,请参阅Like运算符的文档。与Like运算符不同,DirMirror中的所有忽略/排除比较都是不区分大小写的。

将项与列表匹配时,文件和目录的处理方式不同。对于文件,列表模式与文件名(包括扩展名)进行匹配。因此,要排除所有 .pdb 文件,匹配模式为“*.pdb”。

目录与附加了Path.DirectorySeparatorChar(“\”)的键进行匹配。因此,要忽略名为“MyLocalApp\bin”的目录,匹配模式为“*\Mylocalapp\bin\*”(注意末尾的“\*”,并且不区分大小写)。模式“*\MyLocalApp\bin*”也将匹配“mylocalapp\binary”,这可能不是预期的结果。

由于目录匹配的特性,应用程序将始终修改任何目录匹配模式,使其具有前导“*”。如果您输入一个目录匹配,如“\obj\*”,它将在输入时转换为“*\obj\*”。

忽略列表

在处理过程中,与IgnoreList中的条目匹配的文件或目录将出于所有目的而被忽略。它不会从源复制,也不会从目标删除。即使它位于否则要删除的目录下,它也将在目标中保留。在这种情况下,被忽略项的完整路径中所有必需的目录都将被保留,尽管它们的非忽略内容将被删除。

排除列表

ExcludeList中的条目匹配的文件或目录将不会从源复制到目标。如果DeleteExcludes选项对于FolderPair设置为True,则目标中与ExcludeList中的条目匹配的任何项都将被删除。此规则的唯一例外发生在被排除的目录包含一个或多个被忽略项时。有关详细信息,请参阅忽略列表

解释预览和完成计数

要(或已)复制、删除、忽略和排除的目录被视为一个单元。此类目录下的文件和子目录不单独计数。如果镜像的唯一操作是复制单个目录,则该目录的计数将仅为1。该目录下所有文件的总长度将报告在“字节”标题下。

如果FolderPair使用忽略和/或排除列表,您可能会观察到多个文件和目录被报告为(或已经)单独计数,而您并未期望看到。如果忽略和/或排除列表阻止将目录视为单个实体,则会报告各个操作。显然,如果镜像只需要覆盖两个文件并复制另外三个文件,您将看到它们被计数为2个覆盖和3个复制。

DeleteExcludesTrue时会出现一种特殊情况;一个目录匹配ExcludeList,并且一个匹配IgnoreList的项位于该被排除的目录下。在这种情况下,被排除目录下的所有位于被忽略项路径中的目录都将被保留,但它们的(未被忽略的)内容将被列为要(或已)删除。此类内容将在预览显示中单独显示。当一个目录本来会作为整体复制,但其中包含被排除的项时,也会出现类似情况。对于源目录,排除和忽略匹配被视为被排除的项。

源中与忽略模式匹配的项被列为已排除,因此当您完全没有ExcludeList时,可能会看到“已排除”计数。如果源和目标中都有与忽略模式匹配的项,您将看到每个的计数,源的为“已排除”,目标的为“已忽略”。

学会信任应用程序和自己

我当然不会在没有尝试过的情况下使用这样的应用程序。我还会玩转“选项”、“忽略”和“排除”列表,看看它们对我如何工作。作为开发应用程序的一部分,我内置了各种检查其工作方式的方法。我使用的大部分功能和工具仍然可用,我鼓励您使用它们。

单击“预览/操作”显示中ListView中任何非零计数,将显示包含在该计数中的项列表。单击“详细信息”按钮将显示一个单独的窗口,其中显示所有待处理操作的完整项列表。单击任一ListView中任何非零计数将显示包含在该计数中的项列表。通过在“详细信息”显示中双击项,可以在本次运行中取消任何操作。再次双击同一项将恢复已取消的操作。

一旦完成了FolderPair的“预览”,您可以单击“工具”->“显示树”来生成并显示一个相当粗略的ASCII树,其中包含源目录和目标目录,显示将要执行的操作以及它们如何融入目录结构。

您可以点击“工具”->“日志选项”以查看当前日志和所有可用的先前日志。您还可以在此窗口中更改日志选项。

测试DirMirror

对于那些不想在玩转 DirMirror 时冒险丢失自己数据的人,演示下载提供了测试目录和补充信息。在演示目录正下方是 Demo_ReadMe.htm 文件,它描述了如何生成本文顶部的图像所示的结果。还有几个 .txt 文件,提供了运行测试结果的详细报告。在演示目录下有三个子目录:TestSourceTestTargetCopyOfTestTarget。使用 TestSource 作为源,TestTarget 作为目标,以及 CopyOfTestTarget 来重新填充目标以进行额外的试验。这些目录的内容没有意义,但包含各种项目,可以很好地锻炼选项和列表。内容还包括许多文件,其中包含 DirMirror 感兴趣的属性的良好选择(只读、隐藏、系统、压缩和加密)。再次注意,Vista Home... 系统不支持加密。

从命令行

命令行版本 DirMirror.com 接受一个或多个 FolderPair 列表,并执行每个对指定的镜像操作。命令行版本无法定义或修改对,它们必须使用 GUI 版本进行设置。有关更多信息,请在命令行提示符下(与 DirMirror.com 位于同一目录中)键入“DirMirror /?”。

DirMirror的工作原理——详细信息

数据结构和主要类

如上所述并在此重复强调,在整个文章和代码中,最重要的数据元素是 Key。Key 由目录或文件的完整路径组成,其中源或目标目录的完整路径被剥离,留下前导的“\”。例如:给定源目录“C:\Test”,目录“C:\Test\Junk”的 Key 是“\Junk”,而“C:\Test”的 Key 是“\”。

与Windows项名称不同,键区分大小写。“\Junk\a.txt”和“\Junk\A.txt”的键被认为是不同的文件名。这里的概念是,如果您更改了源中项名称的大小写,您会希望该更改反映在目标中。

DirMirror中使用的最重要的数据结构是Dictionary(Of String,Item)。在处理过程中,会创建、修改和处理多个这样的字典。本文使用术语Dictionary来表示这些数据结构。在所有情况下,此类字典的键都是如上定义的Key。

主要类
函数
文件夹对 包含定义源和目标对的所有信息。这包括所有特定于对的忽略和排除列表以及此对的所有选项。
文件夹对 包含用户特定的FolderPair列表。提供Serialize(保存)和Deserialize(加载)此列表的方法。还包含全局忽略和排除列表。
目录列表 表示源目录或目标目录。创建并包装一个包含此实例表示的目录所有子目录的字典。包含用于收集此实例中所有项信息的方法(DirList.GetInfo),构建目录的树状结构。还包含用于构建键的方法。
项目 包装W32_FIND_DATA结构,公开某些应用程序特定的方法和属性。
目录项 继承自Item。包含此实例中所有子目录和文件的Item。公开某些目录和应用程序特定的方法和属性。
文件项 继承自Item。公开某些文件和应用程序特定的方法和属性。
分析 包含分析FolderPair的方法,以确定需要采取哪些操作将源镜像到目标。运行分析的结果就是显示出来的内容,用于在运行镜像操作之前提供镜像的预览。
执行操作 执行构建镜像所需的CopyDeleteOverwrite操作。
WinApi 包含DirMirror使用的各种API的P/Invoke声明。
Logger 提供创建LogFile并写入所需的方法。DirMirror记录其所有目录和文件操作以及一些中间处理步骤的信息。

ItemDirectoryItemFileItem类大致类似于.NET的FileSystemInfoDirectoryInfoFileInfo类。我没有使用.NET类有几个原因,主要是为了速度。

基本分析算法

分析(预览)阶段是DirMirror最复杂的部分。正是对选项以及忽略和排除列表的处理使其如此。然而,基本的(忽略选项和列表)算法相当简单。实际代码更复杂,因为它确实必须处理选项和列表。简单版本可以如下编码:

'Given a Dictionary of all Source Directories (SrcDict)
'  and a Dictionary of all Target Directories (TgtDict)
'  and an empty Dictionary of Directories that have equal keys (DirsUnchanged)
'  and an empty Dictionary of Directories that should be Copied (DirsToCopy)
    Dim SrcKeys(SrcDict.Keys.Count - 1) As String
    SrcDict.Keys.CopyTo(SrcKeys, 0)
    Array.Sort(SrcKeys, New DirNameComparer)
    Dim SrcIndex As Integer = 0
    Do While SrcIndex < SrcKeys.Length
        Dim SrcKey As String = SrcKeys(SrcIndex)
        Dim SrcItem As DirectoryItem = SrcDir(SrcKey)
        If TgtDict.ContainsKey(SrcKey) Then
            DirsUnchanged.Add(SrcKey, TgtDict(SrcKey))
            TgtDict.Remove(SrcKey)
            SrcIndex += 1
        Else
            DirsToCopy.Add(SrcKey,SrcItem)
            SrcIndex += 1
            Do While SrcIndex < SrcKeys.Length AndAlso _
                     SrcKeys(SrcIndex).StartsWith(SrcKey)
                SrcDict.Remove(SrcKeys(srcIndex))
                SrcIndex += 1
            Loop
        End If
    Loop
' At this point, any Directories left in TgtDict are scheduled to be Deleted

然后,代码将以类似的方式检查DirsUnchanged Dictionary中每个目录中的每个文件,将要删除和复制的文件放入名称相似的Dictionary中。对于“相等”的文件,只需忽略它们以进行进一步处理。

何时两个文件相等?

如果两个文件的键匹配,并且它们通过以下函数的相等性测试,则它们被认为是相等的。

Private Shared Function FilesEqual(ByVal SrcFi As FileItem, _
                      ByVal TgtFi As FileItem) As FileResult
'We assume that the file names are equal, else we would not be calling this
  FilesEqual = FileResult.NotEqual            'assume not equal
  Dim TimeEqual As Boolean
  If SrcDir.IsNTFS AndAlso TgtDir.IsNTFS Then
      TimeEqual = SrcFi.LastWriteTimeUTC = TgtFi.LastWriteTimeUTC
  Else
      TimeEqual = DateDiff(DateInterval.Second, SrcFi.LastWriteTimeUTC, _
                  TgtFi.LastWriteTimeUTC) <= 2
  End If
  If TimeEqual AndAlso SrcFi.Length = TgtFi.Length AndAlso _
         AttrMatch(SrcFi, TgtFi) Then
      FilesEqual = FileResult.Equal
  ElseIf SrcFi.LastWriteTimeUTC < TgtFi.LastWriteTimeUTC Then
      FilesEqual = FileResult.Newer
  End If
End Function
Private Shared Function AttrMatch(ByVal F1 As FileItem, _
                         ByVal F2 As FileItem) As Boolean
  Static AttsToTest As FileAttributes = FileAttributes.Encrypted Or _
                                        FileAttributes.Hidden Or _
                                        FileAttributes.ReadOnly Or _
                                        FileAttributes.System
  Dim Comb As FileAttributes = F1.Attributes Xor F2.Attributes
  If Comb = 0 Then Return True
  Comb = Comb And AttsToTest
  If Comb <> 0 Then Return False
  Return True
End Function

要使两个文件被视为相等,它们必须具有相同的LastWriteTimeUTC 必须具有相同的长度。它们还必须匹配某些FileAttribute(只读、隐藏、系统和加密)。请注意,FilesEqual还会确定对于不相等的文件,TgtFile是否比SrcFile新。如果是,该结果将返回给调用者,调用者根据Overwrite选项处理它。

LastWriteTimeUTCs相等性问题必须基于包含FileItems的文件系统。FAT和FAT32文件系统只将LastWriteTime精确到2秒。从NTFS卷复制到FAT32卷的文件很少能保持相同的LastWriteTime。Windows Shell在比较LastWriteTime时使用类似的2秒窗口,所以我的代码至少能做到这一点。

一个DirMirror未处理的更复杂问题是,FAT和FAT32文件系统实际上并不保留LastWriteTimeUTC。Windows根据请求信息时生效的夏令时规则从LastWriteTime推导出该值。最后一点将导致在夏令时更改时(不必要的)Overwriting许多文件。我想修复这个问题,但Windows XP及更早版本不保留有关夏令时规则的历史信息。事实上,我也不认为Vista有,尽管我没有完全检查过。

速度问题

此应用程序或任何类似应用程序有两个耗时的阶段:执行操作(复制、删除等)和扫描目录以获取当前内容。实际上,执行操作是固定成本——除非您可以消除大部分复制等——这正是DirMirror通过只执行最少数量的操作来使目录进入镜像状态而实现的目标。我断言(未经证实),通过复制目录而不是单个子目录和文件可以节省一些时间。当然,不复制源和目标中实际存在且相等的文件和目录比再次复制它们(即在Win资源管理器中拖放或XCOPY脚本)花费的时间更少。

源和目标的初始扫描并非固定成本。根据介质的类型、位置、运行硬件、同时运行的其他程序以及所涉及目录的大小,可能会出现显著的时间差异。在不相关的努力中,我已确定 .NET 类 DirectoryInfoFileInfo 对于本地磁盘来说速度相当快。然而,我发现这些类在扫描网络共享时速度慢得令人痛苦,尤其是当共享位于 Vista 系统上时。映射目录的性能与本地挂载卷的性能大致相同,具体取决于网络速度。

对于 DirMirror,我使用 FindFileFindNextFile API 调用。对于 Vista 主机网络共享上任意大小的目录,FindFileFindNextFile 进行扫描的时间大约是 .NET 类的 1/3。我想我知道为什么会这样,但没有深入研究这个问题,无法在这里推测。只需知道在这种情况下 API 调用速度快得多,并且对于本地磁盘也快约 25% 就足够了。无论您是否使用此应用程序,ItemDirectoryItemFileItem 类以及支持类 WinAPI 在速度是问题的情况下都很有用。

DirMirror 在单独的线程上对源和目标执行其目录扫描。即使在跨不同硬件的多处理器系统上,我也不确定这是否能节省大量时间。我确定它允许我在扫描进行时更改 GUI 以显示“操作/预览”面板。

在本次开发过程中,我对时间花在哪里变得非常感兴趣。因此,我收集了各种执行段的ElapsedT​​ime信息。这些信息仍在收集,可以在日志文件中查看。

如果您不小心点击了一个包含不可用网络共享的FolderPair,您将经历长时间的延迟,因为Windows会确定该共享确实不可用。延迟是您的网络超时值的一个函数,可能会非常令人困扰。此延迟不是DirMirror的功能,也无法由DirMirror取消。请耐心等待,它最终会响应。

我对备份、同步和镜像的定义

备份 备份应用程序通常用于备份系统的大部分或全部内容。通常,它以专有格式保存文件和目录,并维护文件的多个版本。通常,它维护一个单独的目录,记录已备份的内容以及版本所在的位置。每个人都需要一个这样的应用程序来防范灾难性故障或病毒感染。然而,从备份中恢复文件可能非常耗时——因为应用程序会遍历其目录,向您提供可供恢复的选项。
同步 同步应用程序基本上是为了合并两个目录而设计的。它必须处理自上次同步以来两个目录都可能已发生更改的可能性。为了实现这一点,它通常为每个目录维护一个单独的数据集,详细说明每个目录的内容。同步的第一步是根据数据集文档分析目录的当前状态。根据这些信息,它决定应对两个目录进行哪些更改以使其同步。如果您希望避免数据丢失,则对它做出决策所使用的规则有很好的理解非常重要。与备份一样,同步可能会花费很长时间来处理自己的目录。
镜像 像 DirMirror 这样的应用程序绝不会更改源。对目标的更改是通过将其当前内容与源进行比较来完成的。由于没有目录,因此目录不可能过期或损坏。目标中的文件和目录可以直接用于检查或使用正常的 Windows 方法恢复到源。用户有责任知道何时源和目标都发生了更改,并处理如何合并它们。显然,在这种情况下,可能会发生错误,但这是用户造成的错误,而不是软件造成的错误。

正如本节标题所述,这些是我的定义,不一定是您的。市面上有数百甚至数千种备份和同步软件包。像DirMirror这样的并不多。当我第一次寻找这样的应用程序时,我的首要标准是我想要一个能删除主源中不再存在的文件和目录的应用程序。我还想要一个允许我排除某些大文件且在源之外无用的文件,例如 .pch.pdb 文件。也许我Google搜索得不好,但唯一似乎符合我需求的是SyncToy 1.4版。然后,微软用2.0版将其破坏了。一旦我真正查看了“如何”发生损坏,我发现1.4版并不完美。1.4版会在目标中留下孤立目录,并且从不更改目标中目录的创建日期以匹配源中的目录。那时,我决定自己编写。一旦我开始,我便非常投入,以至于唯一能证明这项努力合理性的方法就是撰写这篇文章。

关注点

首先,DirMirror的GUI有点像SyncToy。我非常喜欢1.4版本,并且习惯了它的GUI(比我的更好)。我的只是一个无耻的模仿,但是SyncToy和DirMirror都是免费的,所以没有造成任何伤害。在这个过程中,我学到了一些如何构建那样GUI的方法。DirMirror中有些有趣的技术可能对那些不擅长处理半动态GUI的人有所帮助。

对于少数不精通序列化的用户,DirMirror提供了基于二进制和XML序列化的示例。同一批用户可能对如何在LocalApplicationData中轻松设置和使用特定于应用程序的目录感兴趣。FolderPair定义和日志文件都存储在那里。请查看modMain模块。

那些想看一个使用PropertyGrid更改自己类中属性的实际例子的人,请查看此解决方案中的 PropertyEdit 文件夹。这与FolderPairsFolderPair<Editor(...)>属性的使用一起,还演示了如何定义和使用自己的UITypeEditor来处理List(Of String)。这是基于Mohit Batra的一篇博客,一篇非常出色的作品。

DirMirror演示了在同一个解决方案中构建GUI和CLI版本的一种方法。我只是有两个项目,一个用于GUI,一个用于CLI版本,并根据我希望构建哪个来设置IDE的“启动”项目。CLI是一个后期添加项,因此项目的组织并非最佳。它应该组织成三个项目——一个包含主要处理类的.dll,以及两个可执行文件,一个用于GUI,一个用于CLI。相反,GUI项目包含所有代码,除了CLI版本的“Main”模块。这可以工作,但会导致GUI exe被加载,以便CLI项目可以访问主要处理类。开发人员可能会注意到,CLI可执行文件的复制是在CLI项目的“构建后”步骤中完成的。

对于那些只看文章中代码的人,我将包含以下部分(取自分析的 HandleOptions.vb),以感受一下它的风格。

'Remove Ignored, Excluded, Deleted, and Retained items from the Local masters
Dim Lists() As Dictionary(Of String, Item) = {DirsIgnored, DirsExcluded, _
                                              DirsToDelete, DirsRetained}
For Each Lst As Dictionary(Of String, Item) In Lists
    For Each key As String In Lst.Keys
        SrcDict.Remove(key)
        TgtDict.Remove(key)
    Next
Next

历史

  • 2009年6月9日 -- 版本 1.0 -- 首次提交。
© . All rights reserved.