2012-02-21 85 views
1

我需要将文件的创建或复制/移动事件记录到我将使用的文件夹中,我将使用FileSystemWatcher。问题是,当我在文件夹中粘贴一个文件时,FileSystemWatcher将引发一个创建事件。因此,如果我在该文件夹中共同粘贴10文件,则FileSystemWatcher会引发10个事件。我的要求是如果同时复制文件夹中的所有10个文件,则只会引发一个事件。一次引发FileSystemWatcher的多个事件

请建议。以下是我使用MSDN教程编写的代码。

公共类FileSystemWatcherUtil2 {

public static void Main() 
    { 
     Run(); 
    } 

    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] 
    public static void Run() 
    { 
     /* creation of a new FileSystemWatcher and set its properties */ 
     FileSystemWatcher watcher = new FileSystemWatcher(); 
     watcher.Path = @"C:\Users\TestFolder"; 

     /*watch for internal folder changes also*/ 
     watcher.IncludeSubdirectories = true; 

     /* Watch for changes in LastAccess and LastWrite times, and the renaming of files or directories. */ 
     watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; 

     /* event handlers */ 
     watcher.Changed += new FileSystemEventHandler(OnChanged); 
     watcher.Created += new FileSystemEventHandler(OnChanged); 
     watcher.Deleted += new FileSystemEventHandler(OnChanged); 
     watcher.Renamed += new RenamedEventHandler(OnRenamed); 

     /* watching started */ 
     watcher.EnableRaisingEvents = true; 

     /* user should quit the program to stop watching*/ 
     Console.WriteLine("Press \'q\' to quit the sample."); 
     while (Console.Read() != 'q') ; 
    } 

    /* event handlers definition for changed and renamed */ 
    private static void OnChanged(object source, FileSystemEventArgs e) 
    { 
     Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType); 
    } 

    private static void OnRenamed(object source, RenamedEventArgs e) 
    { 
     Console.WriteLine("File: {0} renamed to {1}", e.OldFullPath, e.FullPath); 
    } 

} 

回答

2

的想法是落实暴露自己CreatedEx事件,这将模拟FileSystemWatcher.Created事件,但会提高每10个Created事件OCCURENCES一个时间FileSystemWatcher的包装。但请记住,我们无法确定所有处理程序Created事件是在单个复制/移动操作的范围内引发的。为了提高这种方法的可靠性,我建议设置一个DirectoryName NotifyFilters value,这样你可以观察到一个目录,但是如果这符合你的要求。也许通过提供更多关于需求的细节,我们可以提供更多的细节,这样方法会更可靠,基本上最重要的是确定大容量复制/移动操作的共同范围,所以当yu复制100个文件和int时同时通过OS启动的其他拷贝操作过程中,你需要从你感兴趣前者操作过滤掉了。所以,文件或许有些共同标准等

  1. FileSystemWatcher实现包装
  2. 暴露自己CreatedEx事件
  3. 认购FileSystemWatcher.Created事件并在处理程序启动斯塔定时器持续200毫秒。如果FileSystemWatcher.Created事件没有发生 - 提出自己的CreatedEx事件,否则重置计时器并等待200ms周期。

定时器的时间段您可以用实验的方式确定,只需复制多个不同大小的文件并查看哪个超时就足够了。

如果您需要提高CreatedEx事件一次整整10个并发事件出现次数 - 您可以在FileSystemWatcher.Created事件处理程序介绍简单的计数器和递减,而当counter==0 - 提高自己的CreatedEx事件。

+1

我认为唯一的真正答案OP的是,你不能,10个文件创建10个事件。这是一个FileSystemWatcher的,而不是一个PasteWatcher;) – Lazarus 2012-02-21 11:13:19

+0

@Lazarus:您可以使用包装这将提高每10个内部'Created'事件OCCURENCES – sll 2012-02-21 11:27:15

+0

没有自己的'CreatedEx'有一次,还是依靠10个内部'Created'事件存在的在彼此的超时期限内(在你的例子中是200ms)?您是否确实能够确定这10个事件是单个粘贴活动的结果,而不是批处理文件复制文件的结果? – Lazarus 2012-02-21 11:35:30

1

FileSystemWatcher无法知道复制是否作为一个操作完成,因为不存在一次复制多个文件等问题。 Windows资源管理器使得看起来像通过使用拖放,但它本质上是多个副本。

如果您希望可以在FileSystemWatcher上编写一个简单的包装器,它可以接受所有创建事件,并且如果它们发生,相隔200毫秒,则会引发“多次创建”事件。

这里是监控创建事件的工作代码。如果您需要和/或公开其他属性,您可以将包装器基于此来监视其他事件。

public class MyWatcher 
{ 
    private FileSystemWatcher watcher = new FileSystemWatcher(); 
    private System.Timers.Timer timer; 
    private object listSync = new object(); 
    private List<FileSystemEventArgs> events = new List<FileSystemEventArgs>(); 

    public delegate void FileSystemMultipleEventHandler(object sender, FileSystemEventArgs[] events); 
    public FileSystemMultipleEventHandler OnMultipleFilesCreated { get; set; } 

    public MyWatcher(string path, NotifyFilters notifyFilters, string filter) 
    { 
     this.watcher.Path = path; 
     this.watcher.Created += FileCreated; 
     watcher.Filter = filter; 
     watcher.EnableRaisingEvents = true; 
    } 

    private void FileCreated(object sender, FileSystemEventArgs e) 
    { 
     if (this.timer != null) 
     { 
      this.timer.Stop(); 
      lock (this.listSync) this.events.Add(e); 
      this.timer.Start(); 
     } 
     else 
     { 
      lock (this.listSync) this.events.Add(e); 
      this.timer = new Timer(200); 
      this.timer.Elapsed += MultipleFilesCreated; 
      this.timer.Start(); 
     } 
    } 

    private void MultipleFilesCreated(object stat, ElapsedEventArgs args) 
    { 
     if (OnMultipleFilesCreated != null) 
     { 
      FileSystemEventArgs[] result; 
      lock (this.listSync) 
      { 
       // make a copy 
       result = events.ToArray(); 
       this.events = new List<FileSystemEventArgs>(); 
      } 
      OnMultipleFilesCreated(this, result); 
     } 
     this.timer.Stop(); 
    } 
} 

我使用锁在这里进行访问的事件列表是线程安全的(定时器VS FileCreated事件)。不使用任何并发收集,因为他们没有ClearAll(),我需要锁定和删除项目一个接一个,还是要重新收集与锁。

+0

感谢马切伊,去尝试你的方法,我也在想同样的。 – user1223082 2012-02-22 08:16:32

+0

如果一切正常,记得将其标记为:-) – 2012-02-22 09:19:59

+0

当文件之一,是非常大的,并得到复制需要更多的时间比我们的默认时间(比如200毫秒)这种做法是失败的答案 – user1223082 2012-02-23 12:47:37