FileSystemWatcher的多个事件的一个提升

时间:2012-02-21 10:26:37

标签: c# .net events

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

请建议。下面是我在MSDN教程的帮助下编写的代码。

public class 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 个答案:

答案 0 :(得分:2)

我们的想法是为FileSystemWatcher实现一个包装器,它会公开自己的CreatedEx事件,该事件将模拟FileSystemWatcher.Created事件,但每10个Created事件发生时会增加一次。但请记住,我们无法确定在单个复制/移动操作的范围内引发所有处理程序Created事件。为了提高这种方法的可靠性,我建议设置一个DirectoryName NotifyFilters value,这样你就可以观察到一个目录,但肯定是符合你的要求。也许通过提供有关需求的更多细节,我们可以提供更多细节,因此方法会更可靠,基本上最重要的是确定批量复制/移动操作的常见范围,所以当你复制100个文件和int时同时由OS启动的其他复制操作正在进行中,您需要从您感兴趣的前一操作中过滤掉它。所以可能是文件的一些常用标准等。

  1. FileSystemWatcher
  2. 实施包装器
  3. 公开自己的CreatedEx活动
  4. 订阅FileSystemWatcher.Created事件,并在处理程序中启动一个计时器,例如200ms。如果未引发FileSystemWatcher.Created事件 - 引发自己的CreatedEx事件,否则重置计时器并等待200毫秒。
  5. 您可以通过实验方式确定的计时器周期,只需复制不同大小的多个文件,并查看哪个超时足够。

    如果你需要为同时发生的10个事件发生一次CreatedEx事件 - 你可以在FileSystemWatcher.Created事件处理程序中引入简单的计数器和减量,并在counter==0时引发自己{ {1}}事件。

答案 1 :(得分:1)

FileSystemWatcher无法知道复制是否作为一个操作完成,因为不存在同时复制多个文件的事情。通过使用拖放,Windows资源管理器看起来就是这样,但它本质上是多个副本。

如果你想要,你可以在FileSystemWatcher周围编写一个简单的包装器来接受所有的Create事件,如果它们发生,比如相隔200ms,则引发一个“Multiple Created”事件。

这是一个监视Create事件的工作代码。如果需要和/或公开其他属性,您可以将其包装在其上以监视其他事件。

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();
    }
}

我在这里使用锁定来访问线程安全的事件列表(timer vs FileCreated事件)。不使用任何并发集合,因为它们没有ClearAll(),我需要逐个锁定和删除项目或者使用锁重新创建集合。