Один рейз для нескольких событий FileSystemWatcher - PullRequest
1 голос
/ 21 февраля 2012

Мне нужно регистрировать события создания или копирования / перемещения файлов в папке, для которой я буду использовать 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 ]

2 голосов
/ 21 февраля 2012

Идея состоит в том, чтобы реализовать оболочку для FileSystemWatcher, которая выставляет собственное событие CreatedEx, которое имитирует событие FileSystemWatcher.Created, но будет вызывать один раз за 10 Created событий.Но имейте в виду, что мы не можем быть уверены, что все события обработчика Created возникают в рамках одной операции копирования / перемещения.Чтобы повысить надежность этого подхода, я бы предложил установить DirectoryName NotifyFilters value, чтобы вы могли наблюдать один каталог, но обязательно, если это соответствует вашим требованиям.Возможно, предоставляя более подробную информацию о ваших требованиях, мы сможем предоставить более подробную информацию, чтобы подход был более надежным, в основном самое важное - это hwo определить общий объем операции массового копирования / перемещения, поэтому, когда вы копируете 100 файлов иВ то же время, когда выполняется другая операция копирования, запущенная ОС, вам нужно отфильтровать ее из предыдущей интересующей вас операции. Так что, возможно, некоторые общие критерии для файлов и т. д.

  1. Реализация оболочкидля FileSystemWatcher
  2. Выставить собственное событие CreatedEx
  3. Подписаться на событие FileSystemWatcher.Created и в обработчике запустить таймер, например, на 200 мс.Если событие FileSystemWatcher.Created не вызвано - вызовите собственное событие CreatedEx, в противном случае сбросьте таймер и подождите 200 мс.

Период таймера, который вы можете определить экспериментальным путем, просто скопируйте несколько файловдругого размера и посмотрите, какое время ожидания достаточно.

Если вам нужно вызвать событие CreatedEx один раз ровно для 10 одновременных событий - вы можете ввести простой счетчик и декремент в обработчике события FileSystemWatcher.Created, а когда counter==0 - поднять собственное CreatedEx событие.

1 голос
/ 21 февраля 2012

FileSystemWatcher не может узнать, было ли копирование выполнено как одна операция, потому что нет такой вещи, как копирование нескольких файлов одновременно. Проводник Windows выглядит так, используя перетаскивание, но по сути это несколько копий.

Если вы хотите, вы можете написать простую оболочку для FileSystemWatcher, которая будет принимать все события Create и, если они произойдут, скажем, с интервалом 200 мс, вызвать событие «Multiple Created».

Вот рабочий код для мониторинга создания событий. Вы можете основывать свою оболочку на этом, чтобы отслеживать другие события, если вам нужно, и / или предоставлять другие свойства.

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

Я использую блокировку здесь, чтобы сделать доступ к списку событий потокобезопасным (таймер против события FileCreated). Не используется никакая одновременная коллекция, потому что у них нет ClearAll (), и мне нужно будет блокировать и удалять элементы по одному или в любом случае заново создавать коллекцию с блокировкой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...