FileSystemWatcher не работает должным образом, когда в каталог одновременно добавляется много файлов

FileSystemWatcher не работает должным образом, когда в каталог одновременно добавляется много файлов...

Watcher просто не находит все файлы в каталоге - только если файлы помещаются в папку один за другим, а не если в папку копируется много файлов одновременно...

Является ли создание потоков решением проблемы или есть другой способ справиться с проблемой?


person Henrik    schedule 15.10.2009    source источник
comment
Имейте в виду, что FileSystemWatcher полагается на ОС, чтобы сигнализировать о добавлении/изменении/удалении файлов и т. д. Так что наличие нескольких экземпляров не поможет.   -  person Agent_9191    schedule 15.10.2009


Ответы (3)


В документации по этому классу подробно описана эта проблема:

Операционная система Windows уведомляет ваш компонент об изменениях файлов в буфере, созданном FileSystemWatcher. При большом количестве изменений за короткое время буфер может переполниться. Это приводит к тому, что компонент теряет отслеживание изменений в каталоге и предоставляет только общее уведомление. Увеличение размера буфера с помощью InternalBufferSize Свойство является дорогостоящим, так как оно исходит из невыгружаемой памяти, которую нельзя выгрузить на диск, поэтому держите буфер как можно меньше, но достаточно большим, чтобы не пропустить ни одного события изменения файла. Чтобы избежать переполнения буфера, используйте NotifyFilter. и свойства IncludeSubdirectories, чтобы можно было отфильтровать нежелательные уведомления об изменении.

Таким образом, потоки, вероятно, не сильно помогут вам в этом случае. Вероятно, вы захотите либо увеличить размер буфера (но насколько он должен быть большим, вполне может зависеть от скорости компьютера и самого диска), либо ограничить интересующие вас файлы, установив соответствующий фильтр.

person Joey    schedule 15.10.2009
comment
И, конечно же, еще один вариант — дополнительно опросить папку на наличие новых файлов и файлов, которые были пропущены. - person Dirk Vollmar; 15.10.2009
comment
Иногда я недооцениваю C#, .Net и т. д., поскольку разработка в мире Microsoft проста (говоря, что Microsoft должна была подумать об этом и для меня...), и веду себя дерзко, поэтому не читаю документацию, а затем трачу часы на такие мелочи, как эта. ржу не могу - person sotn; 01.02.2017
comment
@DirkVollmar Как бы ты это сделал? Можете ли вы искусственно повторно вызвать события для файлов, которые уже находятся в папке? - person Frying Pan; 22.04.2021

C# для меня новичок, и я почти неделю боролся с одной и той же проблемой. У меня было это:

    private void btnWatchFile_Click(object sender, EventArgs e)
    {
        //code to create a watcher and allow it to reise events...
    }

    //watcher onCreate event
    public void onCreated(object sender, FileSystemEventArgs e)
    {
        if (!updateNotifications )
        {
            stringBuilder.Remove(0, stringBuilder.Length);
            stringBuilder.Append(e.FullPath);
            stringBuilder.Append(" ");
            stringBuilder.Append(e.ChangeType.ToString());
            stringBuilder.Append("    ");
            stringBuilder.Append(DateTime.Now.ToString());
            updateNotifications = true;
        }
    }

    //timer to check the flag every X time
    private void timer_Tick(object sender, EventArgs e)
    {
        if (updateNotifications )
        {
            notificationListBox.Items.Insert(0, stringBuilder.ToString());
            updateNotifications = false;
        }
    }

Я даже установил интервал таймера на 1 миллисекунду, но некоторые новые файловые события отсутствовали. Я пытался обновить notificationsListBox из события onCreated, но всегда получал ошибку перекрестной ссылки. Так было до тех пор, пока я не узнал, что событие наблюдателя onCreated выполняется в потоке, отличном от потока основного метода, поэтому, в двух словах, это мое решение:

Я включил public delegate void Action() в качестве атрибута своего класса, а затем использовал Invoke для обновления notificationsListBox из события onCreated. Далее код детали:

    public void onCreated(object sender, FileSystemEventArgs e)
    {
        stringBuilder.Remove(0, stringBuilder.Length);
        stringBuilder.Append(e.FullPath);
        stringBuilder.Append(" ");
        stringBuilder.Append(e.ChangeType.ToString());
        stringBuilder.Append("    ");
        stringBuilder.Append(DateTime.Now.ToString());
        updateNotifications = true;
        Invoke((Action)(() => {notificationListBox.Items.Insert(0, stringBuilder.ToString());}));
    }

Так что таймер и его код больше не нужны. Это отлично работает для меня, и я надеюсь, что это сработает для всех, у кого похожая ситуация. С наилучшими пожеланиями!!!

person 3sley    schedule 17.09.2015

попробуйте что-то вроде этого.

public MainWindow()
    {
        InitializeComponent();

        #region initialise FileSystemWatcher
        FileSystemWatcher watch = new FileSystemWatcher();
        watch.Path = folder;
        watch.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName;
        watch.Filter = ext;
        watch.Changed += new FileSystemEventHandler(OnChanged);
        watch.Created += new FileSystemEventHandler(OnChanged);
        watch.EnableRaisingEvents = true;
        #endregion

    }

 private void OnChanged(object source, FileSystemEventArgs e)
    {
        Application.Current.Dispatcher.BeginInvoke((Action)delegate
        {
          // do your work here. If this work needs more time than it can be processed, not the filesystembuffer overflows but your application will block. In this case try to improve performance here.
        }, System.Windows.Threading.DispatcherPriority.Normal);
    }
person Andreas    schedule 04.07.2012