示例代码显示以下任务:如何设置同步选项。如何显式执行副本的变更检测。如何指定筛选器以控制要在同步中包括的项。如何处理可能在同步期间出现的冲突。如何同步两个副本。显示这些代码示例后,我们提供了应用程序的完整代码,以便您可以生成并运行它。设置同步选项FileSyncOptions 对象用于设置文件同步的几个选项,包括如何检测变更以及是在同步期间删除项还是将它们移到回收站。以下代码示例设置四个选项,其中三个与删除项有关。选项 ExplicitDetectChanges 表示Sync Framework 将不执行变更检测,除非应用程序显式调用 DetectChanges。这将在下一节“执行变更检测”中进行说明。C# FileSyncOptions options = FileSyncOptions.ExplicitDetectChanges | FileSyncOptions.RecycleDeletedFiles | FileSyncOptions.RecyclePreviousFileOnUpdates | FileSyncOptions.RecycleConflictLoserFiles; VBDim options As FileSyncOptions = _ FileSyncOptions.ExplicitDetectChanges Or FileSyncOptions.RecycleDeletedFiles _ Or FileSyncOptions.RecyclePreviousFileOnUpdates _ Or FileSyncOptions.RecycleConflictLoserFiles 执行变更检测默认情况下,Sync Framework 在调用 Synchronize 时对两个副本执行变更检测。通过变更检测,Sync Framework 可以确定应将哪些项从源发送到目标以及哪些项有冲突。通过指定 ExplicitDetectChanges,您可以控制执行变更检测的时间。以下代码示例在调用 Synchronize 前为每个副本调用变更检测。该示例用于说明 DetectChanges,但是它具有使一个变更检测通过的优势而非使两个变更检测通过,当我们以后在应用程序中执行双向同步时,就会出现两个变更检测通过的情况。C# DetectChangesOnFileSystemReplica( replica1RootPath, filter, options); DetectChangesOnFileSystemReplica( replica2RootPath, filter, options); C#publicstaticvoid DetectChangesOnFileSystemReplica( string replicaRootPath, FileSyncScopeFilter filter, FileSyncOptions options) { FileSyncProvider provider = null; try { provider = new FileSyncProvider(replicaRootPath, filter, options); provider.DetectChanges(); } finally { // Release resources.if (provider != null) provider.Dispose(); } } VB DetectChangesOnFileSystemReplica(replica1RootPath, filter, options) DetectChangesOnFileSystemReplica(replica2RootPath, filter, options) VBPublicSharedSub DetectChangesOnFileSystemReplica(ByVal replicaRootPath AsString, ByVal filter As FileSyncScopeFilter, _ ByVal options As FileSyncOptions) Dim provider As FileSyncProvider = NothingTry provider = New FileSyncProvider(replicaRootPath, filter, options) provider.DetectChanges() Finally' Release resources. If provider IsNotNothingThen provider.Dispose() EndIfEndTryEndSub指定静态筛选器可以设置静态筛选器,使其按照名称(包括通配符名称)和属性来排除文件。还可以设置静态筛选器来排除整个子文件夹的内容。或者,可以指定要包括的文件名(包括通配符名称)的显式列表。若要包括在作用域中,文件或文件夹必须传递所有筛选器。例如,如果要从作用域中排除扩展名为 .txt 的所有文件,而在文件列表中指定将 MyFile.txt 显式包括在该作用域中,则由于 MyFile.txt 的扩展名为 .txt,因此将排除 MyFile.txt。以下代码示例使用 FileSyncScopeFilter 对象来创建排除所有 *.lnk 文件的筛选器。筛选器与创建它的提供程序毫无关联。若要将筛选器连接到提供程序,请将该筛选器传递给 FileSyncProvider 的一个构造函数或设置 ScopeFilter 属性。在示例应用程序中,我们在 DetectChangesOnFileSystemReplica() 方法中执行此操作,因为该筛选器仅与变更检测有关。因为该筛选器独立于提供程序,所以对于每个同步会话应只创建一个筛选器;提供程序不应使用不同的筛选器,否则会导致数据不收敛。C# FileSyncScopeFilter filter = new FileSyncScopeFilter(); filter.FileNameExcludes.Add("*.lnk"); VBDim filter AsNew FileSyncScopeFilter() filter.FileNameExcludes.Add("*.lnk") 除了静态筛选器外,还可以在同步期间通过处理提供程序引发的事件排除文件。有关更多信息,请参见控制可同步的文件。处理冲突Sync Framework 检测并解决文件和文件夹的“并发冲突”和“约束冲突”。如果自两个副本上次同步会话以来在这两个副本变更相同的项,则会出现并发冲突。如果将同名的文件或文件夹添加到两个副本,则出现约束冲突。通过保留文件或文件夹的最新变更并删除(或移动)具有较旧变更的文件或文件夹,来解决冲突。对于文件,还可以通过选项指定源还是目标赢得冲突,而与哪个变更首先发生无关。以下代码示例注册 ItemConflicting 和ItemConstraint 事件的事件处理程序,这些事件通过 SyncCallbacks 对象可用。调用的方法按照有利于源的原则解决所有冲突并将信息写入控制台。C#VB SyncCallbacks destinationCallbacks = destinationProvider.DestinationCallbacks; destinationCallbacks.ItemConflicting += new EventHandler(OnItemConflicting); destinationCallbacks.ItemConstraint += new EventHandler(OnItemConstraint); C#publicstaticvoid OnItemConflicting(object sender, ItemConflictingEventArgs args) { args.SetResolutionAction(ConflictResolutionAction.SourceWins); Console.WriteLine("-- Concurrency conflict detected for item " + args.DestinationChange.ItemId.ToString()); } publicstaticvoid OnItemConstraint(object sender, ItemConstraintEventArgs args) { args.SetResolutionAction(ConstraintConflictResolutionAction.SourceWins); Console.WriteLine("-- Constraint conflict detected for item " + args.DestinationChange.ItemId.ToString()); } VBPublicSharedSub OnItemConflicting(ByVal sender AsObject, ByVal args As ItemConflictingEventArgs) args.SetResolutionAction(ConflictResolutionAction.SourceWins) Console.WriteLine("-- Concurrency conflict detected for item " & args.DestinationChange.ItemId.ToString()) EndSubPublicSharedSub OnItemConstraint(ByVal sender AsObject, ByVal args As ItemConstraintEventArgs) args.SetResolutionAction(ConstraintConflictResolutionAction.SourceWins) Console.WriteLine("-- Constraint conflict detected for item " & args.DestinationChange.ItemId.ToString()) EndSub同步两个副本设置选项和筛选器后,应用程序通过实例化 SyncOrchestrator 和调用 Synchronize 方法来同步两个副本。以下代码示例指定每个副本的提供程序、设置选项、注册事件处理程序、指定 Upload 同步方向并调用 Synchronize。调用该方法两次来执行副本之间的双向同步。C# SyncFileSystemReplicasOneWay(replica1RootPath, replica2RootPath, null, options); SyncFileSystemReplicasOneWay(replica2RootPath, replica1RootPath, null, options); C#publicstaticvoid SyncFileSystemReplicasOneWay( string sourceReplicaRootPath, string destinationReplicaRootPath, FileSyncScopeFilter filter, FileSyncOptions options) { FileSyncProvider sourceProvider = null; FileSyncProvider destinationProvider = null; try { // Instantiate source and destination providers, with a null filter (the filter// was specified in DetectChangesOnFileSystemReplica()), and options for both. sourceProvider = new FileSyncProvider( sourceReplicaRootPath, filter, options); destinationProvider = new FileSyncProvider( destinationReplicaRootPath, filter, options); // Register event handlers so that we can write information// to the console. destinationProvider.AppliedChange += new EventHandler(OnAppliedChange); destinationProvider.SkippedChange += new EventHandler(OnSkippedChange); // Use SyncCallbacks for conflicting items. SyncCallbacks destinationCallbacks = destinationProvider.DestinationCallbacks; destinationCallbacks.ItemConflicting += new EventHandler(OnItemConflicting); destinationCallbacks.ItemConstraint += new EventHandler(OnItemConstraint); SyncOrchestrator agent = new SyncOrchestrator(); agent.LocalProvider = sourceProvider; agent.RemoteProvider = destinationProvider; agent.Direction = SyncDirectionOrder.Upload; // Upload changes from the source to the destination. Console.WriteLine("Synchronizing changes to replica: " + destinationProvider.RootDirectoryPath); agent.Synchronize(); } finally { // Release resources.if (sourceProvider != null) sourceProvider.Dispose(); if (destinationProvider != null) destinationProvider.Dispose(); } } VB SyncFileSystemReplicasOneWay(replica1RootPath, replica2RootPath, Nothing, options) SyncFileSystemReplicasOneWay(replica2RootPath, replica1RootPath, Nothing, options) VBPublicSharedSub SyncFileSystemReplicasOneWay(ByVal sourceReplicaRootPath AsString, _ ByVal destinationReplicaRootPath AsString, ByVal filter As FileSyncScopeFilter, _ ByVal options As FileSyncOptions) Dim sourceProvider As FileSyncProvider = NothingDim destinationProvider As FileSyncProvider = NothingTry' Instantiate source and destination providers, with a null filter (the filter' was specified in DetectChangesOnFileSystemReplica()), and options for both. sourceProvider = New FileSyncProvider(sourceReplicaRootPath, filter, options) destinationProvider = New FileSyncProvider(destinationReplicaRootPath, filter, options) ' Register event handlers so that we can write information ' to the console. AddHandler destinationProvider.AppliedChange, AddressOf OnAppliedChange AddHandler destinationProvider.SkippedChange, AddressOf OnSkippedChange ' Use SyncCallbacks for conflicting items.Dim destinationCallbacks As SyncCallbacks = destinationProvider.DestinationCallbacks AddHandler destinationCallbacks.ItemConflicting, AddressOf OnItemConflicting AddHandler destinationCallbacks.ItemConstraint, AddressOf OnItemConstraint Dim agent AsNew SyncOrchestrator() agent.LocalProvider = sourceProvider agent.RemoteProvider = destinationProvider agent.Direction = SyncDirectionOrder.Upload ' Upload changes from the source to the destination. Console.WriteLine("Synchronizing changes to replica: " & destinationProvider.RootDirectoryPath) agent.Synchronize() Finally' Release resources. If sourceProvider IsNotNothingThen sourceProvider.Dispose() EndIfIf destinationProvider IsNotNothingThen destinationProvider.Dispose() EndIfEndTryEndSub完整的代码示例以下代码是此示例的完整代码。本节中上面的示例摘自此处的代码。要运行此代码:创建控制台应用程序项目并将代码添加到该项目。添加对 Microsoft.Synchronzation.dll 和 Microsoft.Synchronzation.Files.dll 的引用。生成项目以创建可执行文件。C#using System; using System.IO; using Microsoft.Synchronization; using Microsoft.Synchronization.Files; namespace Microsoft.Samples.Synchronization { class Program { publicstaticvoid Main(string[] args) { if (args.Length < 2 || string.IsNullOrEmpty(args[0]) || string.IsNullOrEmpty(args[1]) || !Directory.Exists(args[0]) || !Directory.Exists(args[1])) { Console.WriteLine( "Usage: MyExecutableName.exe [valid directory path 1] [valid directory path 2]"); return; } string replica1RootPath = args[0]; string replica2RootPath = args[1]; try { // Set options for the synchronization session. In this case, options specify// that the application will explicitly call FileSyncProvider.DetectChanges, and// that items should be moved to the Recycle Bin instead of being permanently deleted. FileSyncOptions options = FileSyncOptions.ExplicitDetectChanges | FileSyncOptions.RecycleDeletedFiles | FileSyncOptions.RecyclePreviousFileOnUpdates | FileSyncOptions.RecycleConflictLoserFiles; // Create a filter that excludes all *.lnk files. The same filter should be used // by both providers. FileSyncScopeFilter filter = new FileSyncScopeFilter(); filter.FileNameExcludes.Add("*.lnk"); // Explicitly detect changes on both replicas before syncyhronization occurs.// This avoids two change detection passes for the bidirectional synchronization // that we will perform. DetectChangesOnFileSystemReplica( replica1RootPath, filter, options); DetectChangesOnFileSystemReplica( replica2RootPath, filter, options); // Synchronize the replicas in both directions. In the first session replica 1 is// the source, and in the second session replica 2 is the source. The third parameter// (the filter value) is null because the filter is specified in DetectChangesOnFileSystemReplica(). SyncFileSystemReplicasOneWay(replica1RootPath, replica2RootPath, null, options); SyncFileSystemReplicasOneWay(replica2RootPath, replica1RootPath, null, options); } catch (Exception e) { Console.WriteLine("\nException from File Sync Provider:\n" + e.ToString()); } } // Create a provider, and detect changes on the replica that the provider// represents.publicstaticvoid DetectChangesOnFileSystemReplica( string replicaRootPath, FileSyncScopeFilter filter, FileSyncOptions options) { FileSyncProvider provider = null; try { provider = new FileSyncProvider(replicaRootPath, filter, options); provider.DetectChanges(); } finally { // Release resources.if (provider != null) provider.Dispose(); } } publicstaticvoid SyncFileSystemReplicasOneWay( string sourceReplicaRootPath, string destinationReplicaRootPath, FileSyncScopeFilter filter, FileSyncOptions options) { FileSyncProvider sourceProvider = null; FileSyncProvider destinationProvider = null; try { // Instantiate source and destination providers, with a null filter (the filter// was specified in DetectChangesOnFileSystemReplica()), and options for both. sourceProvider = new FileSyncProvider( sourceReplicaRootPath, filter, options); destinationProvider = new FileSyncProvider( destinationReplicaRootPath, filter, options); // Register event handlers so that we can write information// to the console. destinationProvider.AppliedChange += new EventHandler(OnAppliedChange); destinationProvider.SkippedChange += new EventHandler(OnSkippedChange); // Use SyncCallbacks for conflicting items. SyncCallbacks destinationCallbacks = destinationProvider.DestinationCallbacks; destinationCallbacks.ItemConflicting += new EventHandler(OnItemConflicting); destinationCallbacks.ItemConstraint += new EventHandler(OnItemConstraint); SyncOrchestrator agent = new SyncOrchestrator(); agent.LocalProvider = sourceProvider; agent.RemoteProvider = destinationProvider; agent.Direction = SyncDirectionOrder.Upload; // Upload changes from the source to the destination. Console.WriteLine("Synchronizing changes to replica: " + destinationProvider.RootDirectoryPath); agent.Synchronize(); } finally { // Release resources.if (sourceProvider != null) sourceProvider.Dispose(); if (destinationProvider != null) destinationProvider.Dispose(); } } // Provide information about files that were affected by the synchronization session.publicstaticvoid OnAppliedChange(object sender, AppliedChangeEventArgs args) { switch (args.ChangeType) { case ChangeType.Create: Console.WriteLine("-- Applied CREATE for file " + args.NewFilePath); break; case ChangeType.Delete: Console.WriteLine("-- Applied DELETE for file " + args.OldFilePath); break; case ChangeType.Update: Console.WriteLine("-- Applied OVERWRITE for file " + args.OldFilePath); break; case ChangeType.Rename: Console.WriteLine("-- Applied RENAME for file " + args.OldFilePath + " as " + args.NewFilePath); break; } } // Provide error information for any changes that were skipped.publicstaticvoid OnSkippedChange(object sender, SkippedChangeEventArgs args) { Console.WriteLine("-- Skipped applying " + args.ChangeType.ToString().ToUpper() + " for " + (!string.IsNullOrEmpty(args.CurrentFilePath) ?VBImports System Imports System.IO Imports Microsoft.Synchronization Imports Microsoft.Synchronization.Files Namespace Microsoft.Samples.Synchronization Class Program ' File synchronization provider requires applications to use the multithreaded apartment (MTA) ' threading model. This is specified by using the MTAThread attribute. _ PublicSharedSub Main(ByVal args AsString()) If args.Length < 2 OrElseString.IsNullOrEmpty(args(0)) OrElseString.IsNullOrEmpty(args(1)) OrElseNot Directory.Exists(args(0)) OrElseNot Directory.Exists(args(1)) Then Console.WriteLine("Usage: MyExecutableName.exe [valid directory path 1] [valid directory path 2]") ExitSubEndIfDim replica1RootPath AsString = args(0) Dim replica2RootPath AsString = args(1) Try' Set options for the synchronization session. In this case, options specify ' that the application will explicitly call FileSyncProvider.DetectChanges, and ' that items should be moved to the Recycle Bin instead of being permanently deleted. Dim options As FileSyncOptions = _ FileSyncOptions.ExplicitDetectChanges Or FileSyncOptions.RecycleDeletedFiles _ Or FileSyncOptions.RecyclePreviousFileOnUpdates _ Or FileSyncOptions.RecycleConflictLoserFiles ' Create a filter that excludes all *.lnk files. The same filter should be used ' by both providers.Dim filter AsNew FileSyncScopeFilter() filter.FileNameExcludes.Add("*.lnk") ' Explicitly detect changes on both replicas before syncyhronization occurs. ' This avoids two change detection passes for the bidirectional synchronization ' that we will perform. DetectChangesOnFileSystemReplica(replica1RootPath, filter, options) DetectChangesOnFileSystemReplica(replica2RootPath, filter, options) ' Synchronize the replicas in both directions. In the first session replica 1 is ' the source, and in the second session replica 2 is the source. The third parameter' (the filter value) is null because the filter is specified in DetectChangesOnFileSystemReplica(). SyncFileSystemReplicasOneWay(replica1RootPath, replica2RootPath, Nothing, options) SyncFileSystemReplicasOneWay(replica2RootPath, replica1RootPath, Nothing, options) Catch e As Exception Console.WriteLine(vbLf & "Exception from File Sync Provider:" & vbLf & e.ToString()) EndTryEndSub' Create a provider, and detect changes on the replica that the provider ' represents. PublicSharedSub DetectChangesOnFileSystemReplica(ByVal replicaRootPath AsString, ByVal filter As FileSyncScopeFilter, _ ByVal options As FileSyncOptions) Dim provider As FileSyncProvider = NothingTry provider = New FileSyncProvider(replicaRootPath, filter, options) provider.DetectChanges() Finally' Release resources. If provider IsNotNothingThen provider.Dispose() EndIfEndTryEndSubPublicSharedSub SyncFileSystemReplicasOneWay(ByVal sourceReplicaRootPath AsString, _ ByVal destinationReplicaRootPath AsString, ByVal filter As FileSyncScopeFilter, _ ByVal options As FileSyncOptions) Dim sourceProvider As FileSyncProvider = NothingDim destinationProvider As FileSyncProvider = NothingTry' Instantiate source and destination providers, with a null filter (the filter' was specified in DetectChangesOnFileSystemReplica()), and options for both. sourceProvider = New FileSyncProvider(sourceReplicaRootPath, filter, options) destinationProvider = New FileSyncProvider(destinationReplicaRootPath, filter, options) ' Register event handlers so that we can write information ' to the console. AddHandler destinationProvider.AppliedChange, AddressOf OnAppliedChange AddHandler destinationProvider.SkippedChange, AddressOf OnSkippedChange ' Use SyncCallbacks for conflicting items.Dim destinationCallbacks As SyncCallbacks = destinationProvider.DestinationCallbacks AddHandler destinationCallbacks.ItemConflicting, AddressOf OnItemConflicting AddHandler destinationCallbacks.ItemConstraint, AddressOf OnItemConstraint Dim agent AsNew SyncOrchestrator() agent.LocalProvider = sourceProvider agent.RemoteProvider = destinationProvider agent.Direction = SyncDirectionOrder.Upload ' Upload changes from the source to the destination. Console.WriteLine("Synchronizing changes to replica: " & destinationProvider.RootDirectoryPath) agent.Synchronize() Finally' Release resources. If sourceProvider IsNotNothingThen sourceProvider.Dispose() EndIfIf destinationProvider IsNotNothingThen destinationProvider.Dispose() EndIfEndTryEndSub' Provide information about files that were affected by the synchronization session. PublicSharedSub OnAppliedChange(ByVal sender AsObject, ByVal args As AppliedChangeEventArgs) SelectCase args.ChangeType Case ChangeType.Create Console.WriteLine("-- Applied CREATE for file " & args.NewFilePath) ExitSelectCase ChangeType.Delete Console.WriteLine("-- Applied DELETE for file " & args.OldFilePath) ExitSelectCase ChangeType.Update Console.WriteLine("-- Applied OVERWRITE for file " & args.OldFilePath) ExitSelectCase ChangeType.Rename Console.WriteLine(("-- Applied RENAME for file " & args.OldFilePath & " as ") & args.NewFilePath) ExitSelectEndSelectEndSub' Provide error information for any changes that were skipped. PublicSharedSub OnSkippedChange(ByVal sender AsObject, ByVal args As SkippedChangeEventArgs) Console.WriteLine(("-- Skipped applying " & args.ChangeType.ToString().ToUpper() & " for ") & (If(NotString.IsNullOrEmpty(args.CurrentFilePath), args.CurrentFilePath, args.NewFilePath)) & " due to er