FileSystemWatcher для уведомления - PullRequest
4 голосов
/ 25 сентября 2010

Я создаю приложение для Windows, которое использует FileSystemWatcher.FileSystemWatcher следит за некоторым каталогом на предмет изменений.И каждый раз, когда какой-либо файл добавляется в этот каталог, FileSystemWatcher должен добавлять информацию об этом файле в файл XML.Все работает нормально, но, когда я добавляю, например, 100 файлов одновременно (скажем, какое-то приложение добавляет эти файлы в каталог), в этом XML-файле появляется информация не о каждом файле.

Я хочу использовать Очередь.И использовать его для добавления предметов в эту коллекцию.И использовать таймер.Таймер добавит информацию в XML из этой коллекции.Это хорошая идея?

Может кто-нибудь посоветовать мне, что делать?


Так что я думаю, что должен создать приложение Windows и службу Windows.WinApp будет только добавлять информацию в EventLog, а служба Windows будет считывать информацию EventLog и записывать ее в XML.Я думаю, что это будет лучший способ сделать это.Жду доброго совета

Ответы [ 4 ]

2 голосов
/ 25 сентября 2010

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

Сохраняйте код обработки событий коротким насколько это возможно.

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

Один относительно простой способ сделать это - использовать ThreadPool.QueueUserWorkItem . Это означает, что ваш журнал изменений по-прежнему не будет на 100% синхронизирован с состоянием файловой системы (из-за задержки, вызванной использованием отдельных потоков и очереди), но он может быть более точным, и это, кажется, является вашей главной задачей. Вам нужно убедиться, что ваш WaitCallback, вызванный пулом потоков, является поточно-ориентированным (например, записи в ваш журнал изменений не происходят одновременно без lock() или подобного), и знать, что нет никаких гарантий, что записи в журнале изменений будет написано в том порядке, в котором они произошли (хотя мне сомнительно, гарантирует ли это FileSystemWatcher в любом случае).

Также в соответствии с инструкциями для API - убедитесь, что вы фильтруете возможный набор событий, чтобы вам перезванивали только те, которые вам абсолютно необходимо видеть:

Чтобы избежать переполнения буфера, используйте NotifyFilter и IncludeSubdirectories properties так что вы можете отфильтровать уведомления о нежелательных изменениях.

2 голосов
/ 25 сентября 2010

Как пишет Майкл Стум в своем ответе, вы можете попробовать увеличить размер буфера (FileSystemWatcher.InternalBufferSize).Однако обратите внимание, что вы не должны устанавливать это значение слишком высоким.Кроме того, ИМХО, возможно, это только временное исправление, посмотрим, что произойдет, если вы добавите в свою папку еще больше файлов.

Я читал о некоторых других вещах, которые вы можете предпринять, если увеличение размера буфера нене помогите:

  • Если вы подписаны на события уведомлений FileSystemWatcher, постарайтесь сделать ваш обработчик событий как можно короче;то есть.убедитесь, что исполнение не задержится там надолго.Если вам нужно выполнить изрядное количество работы для каждого файла, вы можете попытаться запустить отдельный поток и выполнить там обработку;ваш обработчик событий может затем очень быстро вернуться к вызывающей стороне (и уведомление о файле будет удалено из буфера / очереди быстрее).

  • Не используйте дополнительную информацию, предоставленную FileSystemWatcher кроме основного уведомления, что что-то изменилось.Как только вы получите любое уведомление об изменении файла, подождите короткий промежуток времени, пока не придет больше уведомлений (т. Е. Дождитесь последнего уведомления из 100 одновременных уведомлений об изменении файла).Затем перечислите содержимое каталога вручную и перенесите необходимую информацию в ваш XML.

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

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

2 голосов
/ 25 сентября 2010

FileSystemWatcher имеет внутренний буфер для изменений.Если быстрых изменений много, буфер может не перехватить все события.

Попробуйте увеличить InternalBufferSize до чего-то большего.

Вы можете установитьбуфер до 4 КБ или более, но он не должен превышать 64 КБ.Для лучшей производительности используйте несколько 4 КБ на компьютерах с процессорами Intel.

Система уведомляет компонент об изменениях файлов и сохраняет эти изменения в буфере, который компонент создает, и передает его API-интерфейсам.Каждое событие может использовать до 16 байт памяти, не включая имя файла.Если за короткое время произойдет много изменений, буфер может переполниться.Это приводит к тому, что компонент теряет отслеживание изменений в каталоге, и он будет предоставлять только общее уведомление.Увеличение размера буфера имеет следующие последствия:

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

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

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

Также, как уже было сказано, установите для NotifyFilter наименьшие необходимые флаги, которые могут быть NotifyFilters.LastWrite , если вы хотите отслеживать только изменения.

1 голос
/ 25 сентября 2010

Если я правильно понимаю: вы смотрите каталог, и когда одновременно добавляется много файлов, вы видите только некоторые из них с FileSystemWatcher.

Пробовали ли вы следующее: в обработчике событий для OnCreated просто перейдите в файловую систему и получите полное содержимое каталога, независимо от того, что вам сообщает событие?

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