FileSystemWatcher получает слишком много событий

Я пытаюсь реализовать наблюдатель за файлами, который вызовет событие, если содержимое файла было изменено. Проблема в том, что после изменения файла, который я смотрю, я получаю 2 события. (Я хочу получить его только один раз)

_automationStatusWatcher = new FileSystemWatcher(fileInfo.Directory.FullName,
                                                 fileInfo.Name);
_automationStatusWatcher.NotifyFilter = NotifyFilters.LastWrite;
_automationStatusWatcher.Changed += OnAutomationStatusChanged;
_automationStatusWatcher.EnableRaisingEvents = true;

Файл, который я смотрю, не предназначен для повторного создания/перемещения/удаления/что-то еще. его цель - быть файлом базы данных xml, который мне нужно отслеживать после его изменения. я хочу получить только одно событие при изменении файла и игнорировать другие события.

Как я могу это сделать?


person user829174    schedule 22.02.2012    source источник
comment
провести 2 очень близких события как одно... это мое текущее решение.   -  person Bolu    schedule 22.02.2012


Ответы (6)


Руководство:

Примечание

Обычные операции с файловой системой могут вызывать более одного события. Например, когда файл перемещается из одного каталога в другой, могут возникнуть несколько событий OnChanged и некоторые события OnCreated и OnDeleted. Перемещение файла — это сложная операция, состоящая из нескольких простых операций, поэтому возникает несколько событий. Аналогичным образом некоторые приложения (например, антивирусное программное обеспечение) могут вызывать дополнительные события файловой системы, обнаруживаемые FileSystemWatcher.

person CodeCaster    schedule 22.02.2012
comment
Я это понимаю, но есть ли конкретное событие для проверки только того, был ли файл изменен? этот файл не предназначен для перемещения в другую папку или создания. - person user829174; 22.02.2012
comment
Не уверен, что вы должны -1 его ответ, вы не указали ничего, что хотели бы знать. Как мне это сделать? ужасный вопрос. - person dsingleton; 22.02.2012
comment
@ user829174 ваш вопрос не ясен. Как указано в руководстве, несколько событий могут быть вызваны в разных случаях. Пожалуйста, опубликуйте воспроизводимый тестовый пример, если вы хотите получить полезные ответы. Когда происходит несколько событий, когда вы просто пишете в файл? Или вы перемещаете файл? У вас работает антивирусный сканер? - person CodeCaster; 22.02.2012
comment
извините за это, я по ошибке поставил ему -1. я отредактировал свой вопрос, чтобы быть более конкретным. Благодарность - person user829174; 22.02.2012
comment
@user829174 user829174, вы можете выбрать предполагаемое решение обработки нескольких событий как одного в течение определенного периода времени. Так что сохраняйте статус LastModified в переменной и игнорируйте любые новые события, происходящие в течение разумного промежутка времени от LastModified (зависит от его использования, но нескольких секунд должно быть достаточно). - person CodeCaster; 22.02.2012

Некоторое время назад мне пришлось столкнуться с этой проблемой. Я хотел получать уведомления, когда файл был создан. Проблема заключалась в том, что событие запускается, когда файл все еще пуст или в него все еще выполняется запись, а не когда новый файл закрывается.

Решение состояло в том, чтобы создать файл, используя временное имя, а по завершении переименовать файл в его окончательное имя. Затем я наблюдал за событием переименования.

Вы можете назвать файл myfile.tmp во время записи в него, а когда закончите, переименовать его в myfile.xml и наблюдать за событием переименования.

person Olivier Jacot-Descombes    schedule 22.02.2012

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

_automationStatusWatcher.Changed -= OnAutomationStatusChanged;

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

private bool _inStatusChange = false;
private void OnAutomationStatusChanged(object sender, args...)
{
    if (_inStatusChange)
    {
        return;
    }
    else
    {
         _inStatusChange = true;
        //do work
        _inStatusChange = false;

    }
}

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

person JamieB    schedule 22.02.2012

Я тоже встречаюсь с этой проблемой, теперь я узнал так:

new Thread(() => {
            while (true) {
                var r = watch.WaitForChanged(WatcherChangeTypes.All);
                this.Invoke(new ThreadStart(() => {
                    listBox1.Items.Add(string.Format("{0} {1} {2}", DateTime.Now, r.Name, r.ChangeType));
                }));
            }
        }) { IsBackground = true }.Start();

очень похоже на nio в java

person Inshua    schedule 27.12.2013

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

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

person brgerner    schedule 22.02.2012

Если вы посмотрите документацию для FileSystemWatcher, там сказано, что он будет срабатывать несколько раз.

Moving a file is a complex operation that consists of multiple simple operations, therefore raising multiple events. Likewise, some applications (for example, antivirus software) might cause additional file system events that are detected by FileSystemWatcher.

Я бы рекомендовал использовать какой-то механизм очередей, чтобы у вас не было нескольких действий с одним и тем же файлом.

person dsingleton    schedule 22.02.2012