FileSystemWatcher против опроса, чтобы наблюдать за изменениями файла

152

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

Будет FileSystemWatcherили опрос по таймеру будет лучшим вариантом. Я использовал оба метода в прошлом, но не широко.

Какие проблемы (производительность, надежность и т. Д.) Возникают при использовании любого из этих методов?

Джон Такабери
источник
3
FileSystemWatcher - это утечка абстракций, на которую нельзя положиться ни для чего, кроме самых простых случаев. См. Здесь: stackoverflow.com/a/22768610/129130
Стейн Осмул
1
Хотите добавить ссылку для ссылки на этот ответ Раймонда Чена (эксперт Microsoft) на тему надежности FileSystemWatcher . И его блог: Старая новая вещь (например, поиск FileSystemWatcher).
Стейн Осмул

Ответы:

105

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

Изменить: Если у вас есть пользовательский интерфейс, вы также можете дать своему пользователю возможность «обновлять» изменения вместо опроса. Я бы сочетал это с наблюдателем файловой системы.

Джейсон Джексон
источник
11
Я видел, если упасть тоже. Решение, которое мы использовали, заключается в том, чтобы обернуть наш собственный класс, где класс-оболочка ТАКЖЕ использует таймер для проверки того, что наблюдатель все еще работает.
Джоэл Коухорн
Мы делаем нечто подобное - после обработки файла, переданного в событие FileCreated, мы выполняем ручную проверку на наличие любых других новых файлов перед возвратом. Это, кажется, смягчает любые проблемы, возникающие с большим количеством файлов, поступающих одновременно.
Джон Симбл
4
Я полагаю, что мы проверили его в XP и Server 2003 на локальном каталоге и на общем файловом ресурсе, и у нас были XP-машины на местах. У нас были проблемы с локальным каталогом и общим доступом к файлам. Одной из вероятных причин, по которой мы пришли, было копирование / создание большого количества файлов за короткое время в каталоге.
Джейсон Джексон
5
Не очень конструктивно и не профессионально утверждать, что «однажды я видел призрака». Похоже, что люди в потоке, упомянув документ msdn о переполнениях буфера, не допускающих вывода страниц, могут объяснить ваши проблемы. Вы пытались использовать подход Брента?
v.oddou
4
Я только что купил газовый датчик на Amazon, и меня поразило, как много людей сказали, что он не работает, когда они явно не откалибровали его правильно или даже не знали о калибровке ... FileSystemWatcher имеет ограничения с высоким трафиком от его размер буфера. Почти гарантировано, что причина этого "провала". Это легко объясняется в документации, и существуют обходные пути, которые обеспечивают очень надежную работу (как указано ниже). Это не очень хороший ответ, чтобы просто сказать «ошибаться, что-то не сработало, но не знаю почему ... никто не должен полагаться на это».
u8it
60

Самая большая проблема, с которой я столкнулся, - это отсутствие файлов при заполнении буфера. Легко исправить, просто увеличьте буфер. Помните, что он содержит имена файлов и события, поэтому увеличьте его до ожидаемого количества файлов (методом проб и ошибок). Он использует память, которая не может быть выгружена из памяти, поэтому он может заставить другие процессы отображать страницу, если память становится неактивной.

Вот статья MSDN о буфере: FileSystemWatcher .. ::. InternalBufferSize Свойство

По MSDN:

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

Мы используем 16 МБ из-за большой партии, ожидаемой за один раз. Работает нормально и никогда не пропускает файл.

Мы также читаем все файлы перед тем, как начинать обрабатывать даже один файл ... надежно кэшируем имена файлов (в нашем случае, в таблицу базы данных), а затем обрабатываем их.

Для проблем с блокировкой файлов я порождаю процесс, который ждет, пока файл будет разблокирован, и ждет одну секунду, затем две, затем четыре и так далее. Мы никогда не опрашиваем. Это было в производстве без ошибок около двух лет.


источник
12
Переполнение буфера? О, вы имеете в виду переполнение стека.
TheFlash
1
Начиная с .NET 3.5: «Вы можете установить буфер на 4 КБ или больше, но он не должен превышать 64 КБ»
Брэд
9
Как вы используете 16 МБ, если максимальный внутренний буфер для FileSystemWatcher составляет 64 КБ?
BK
1
@ Jarvis, буфер - это временное хранилище, сконфигурированное для хранения информации во время ее передачи до тех пор, пока она не может быть обработана, это обычно означает FIFO или очередь, поскольку вы хотите обрабатывать запросы в порядке их поступления, однако в некоторых процессах, таких как рекурсия в программах используется структура FILO или стека. В этом случае мы определенно
ссылаемся на
1
petermeinl.wordpress.com/2015/05/18/tamed-filesystemwatcher В этом посте рассказывается о надежных оболочках стандартного FileSystemWatcher (FSW), исправляющих проблемы, которые обычно возникают при его использовании для мониторинга файловой системы в реальных приложениях.
Kiquenet
35

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

Как упомянуто выше @ChillTemp, наблюдатель может не работать с общими папками, отличными от Windows. Например, он не будет работать на подключенных дисках Novell.

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

Брент Роквуд
источник
4
Наблюдатель за файловой системой может начать вызывать множество событий в быстрой последовательности. Если вы не можете выполнить свой обработчик событий хотя бы так же быстро, как они запускаются, в конечном итоге обработчик начнет отбрасывать события на полу, и вы пропустите вещи.
Брент Роквуд
17

Также обратите внимание, что наблюдатель файловой системы не надежен на общих файловых ресурсах. Особенно, если общий файловый ресурс размещен на сервере, отличном от Windows. FSW не должен использоваться для чего-то критического. Или следует использовать при случайном опросе, чтобы убедиться, что он ничего не пропустил.

chilltemp
источник
3
Microsoft признала, что это не надежно на общих файловых ресурсах не-Windows? Мы, безусловно, испытываем это на собственном опыте с момента перехода с общего ресурса Windows на общий ресурс SMB на базе Linux.
Шон
1
Не то, чтобы я знал. И я уверен, что это будет просто игра обвинений между различными поставщиками.
Chilltemp
1
У нас возникли проблемы с наблюдателем файловой системы на подключенных дисках. Если карта отключается, а затем повторно подключается, средство просмотра файлов больше не вызывает изменений. Легко решается, но все же удар по наблюдателю файловой системы ИМХО.
Ричард Дорман
11

Лично я использовал в FileSystemWatcherпроизводственной системе, и она работала нормально. За последние 6 месяцев у него не было ни одного сбоя 24x7. Это мониторинг одной локальной папки (которая является общей). У нас относительно небольшое количество файловых операций, которые он должен обрабатывать (10 событий в день). Это не то, о чем мне когда-либо приходилось беспокоиться. Я бы использовал это снова, если бы мне пришлось переделать решение.

Джим
источник
7

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

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

У меня нет опыта в удаленном просмотре файлов и не в Windows.

Я бы посчитал, что опрос файла является избыточным и не стоит лишних затрат, если вы по своей сути не доверяете FileSystemWatcherили не испытываете ограничений, которые все остальные здесь перечислили (общие папки, отличные от Windows, и удаленный просмотр файлов).

инерция зрения
источник
5

Я бы пошел с опросом.

Проблемы с сетью приводят FileSystemWatcherк ненадежности (даже при перегрузке события ошибки).

голубоватый
источник
5

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

Джон Нортон
источник
Я столкнулся с той же проблемой, но это было неожиданно для меня, так как FileSystemWatcher находился на том же сервере Windows, который совместно использует папку с использованием NFS. факт совместного использования папки с NFS приводит к тому, что файловая система-наблюдатель не видит файлы, созданные с помощью общего ресурса, удаленно (то есть из Linux, который отображает общий ресурс), в то время как, если я записываю файл в ту же самую папку под наблюдением, запускается файловая система. похоже, что сервер NFS записывает файлы с использованием нижнего уровня, а уровень API, который запускает функцию файловой системы, не задействован, у кого-нибудь есть дополнительная информация?
Мосе Боттачини
3

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

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

Кроме того, у меня не было никаких проблем с локальными папками, независимо от того, были ли они общими или нет.

треб
источник
3

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

private void Watcher_Created(object sender, FileSystemEventArgs e)
{
    Task.Run(() => MySubmit(e.FullPath));
}
spludlow
источник
2

На мой взгляд, использование FSW и опросов - пустая трата времени и ресурсов, и я удивлен, что опытные разработчики предлагают это. Если вам нужно использовать опрос для проверки любых «пропусков FSW», то вы, естественно, можете вообще отказаться от FSW и использовать только опрос.

В настоящее время я пытаюсь решить, буду ли я использовать FSW или опрос для проекта, который я разрабатываю. Прочитав ответы, очевидно, что есть случаи, когда ЖСБ полностью удовлетворяет потребности, а в других случаях вам нужен опрос. К сожалению, ни один из ответов на самом деле не касался разницы в производительности (если есть), только проблемы «надежности». Кто-нибудь может ответить на эту часть вопроса?

EDIT: nmclean ТОЧКА за правомерность использования как FSW и опроса (вы можете прочитать обсуждение в комментариях, если вы заинтересованы) , как представляется, очень рациональное объяснение , почему не может быть ситуации, с использованием как в FSW и опроса является эффективный. Спасибо, что пролили свет на это для меня (и для всех, кто придерживается того же мнения), nmclean .

ThunderGr
источник
1
Что если вы хотите как можно быстрее реагировать на изменения файлов? Например, если вы проводите опрос один раз в минуту, у вас может возникнуть задержка в 1 минуту между изменением файла и принятием вашего приложения изменений. Событие ЖСБ, вероятно, будет инициировано задолго до этого. Таким образом, используя оба, вы обрабатываете события с минимальной задержкой, насколько это возможно, но также выбираете пропущенные события, если они есть.
rom99
@ rom99 Точно моя точка зрения. Если FSW ненадежен в тех случаях, когда вам нужен быстрый ответ, нет смысла его использовать, поскольку у вас будут случаи, когда быстрый ответ не будет, поэтому ваше приложение будет ненадежным. Опрос с более короткими интервалами, в потоке, будет то, что вам нужно сделать. Делая оба , означает, что у вас есть допуск во время ответа, которое охватывает опрос, поэтому, почему бы не использовать только опрос?
ThunderGr
5
@ThunderGr "Таким образом, ваше приложение будет ненадежным." - Во многих случаях скорость не является обязательным условием для надежности. Работа должна быть выполнена, но она может подождать некоторое время. Если мы объединим медленный, надежный опрос с быстрым, ненадежным FSW, мы получим приложение, которое всегда надежно, а иногда быстро, что лучше, чем надежно и никогда не быстро. Мы можем удалить FSW и достичь того же максимального времени отклика, выполняя постоянный опрос, но это происходит за счет отзывчивости остальной части приложения, поэтому это следует делать, только если немедленный ответ абсолютно необходим.
nmclean
2
Теперь, почему вышеупомянутое плохой аргумент? Потому что, хотя нам все еще нужен доступ к диску, он нам нужен меньше . Точно так же вы можете опрашивать меньше. Тот факт, что мы все еще проверяем все файлы, не означает, что рабочая нагрузка одинакова. Ваше утверждение «опрос дорогостоящего процессора с FSW или нет» неверно . Разгружая проблему «неотложности» в FSW, мы можем изменить опрос на незанятую задачу с низким приоритетом, так что занятость приложения в любой момент времени резко снижается, в то же время обеспечивая «обработку» непосредственности. Вы просто не можете достичь того же баланса с помощью одного опроса.
nmclean
9
@nmclean Спасибо, что нашли время и энергию, чтобы уточнить это так, как вы. Когда вы говорите так, это, безусловно, имеет больше смысла. Точно так же, как бывают случаи, когда кеш не подходит для вашей конкретной проблемы, FSW (когда он оказывается ненадежным) может не подойти. Оказывается, ты был прав с самого начала. Мне жаль, что мне потребовалось так много времени, чтобы получить его.
ThunderGr
1

Рабочее решение для работы с созданием события вместо изменения

Даже для копирования, вырезания, вставки, перемещения.

class Program
{        

        static void Main(string[] args)
        {
            string SourceFolderPath = "D:\\SourcePath";
            string DestinationFolderPath = "D:\\DestinationPath";
            FileSystemWatcher FileSystemWatcher = new FileSystemWatcher();
            FileSystemWatcher.Path = SourceFolderPath;
            FileSystemWatcher.IncludeSubdirectories = false;
            FileSystemWatcher.NotifyFilter = NotifyFilters.FileName;   // ON FILE NAME FILTER       
            FileSystemWatcher.Filter = "*.txt";         
             FileSystemWatcher.Created +=FileSystemWatcher_Created; // TRIGGERED ONLY FOR FILE GOT CREATED  BY COPY, CUT PASTE, MOVE  
            FileSystemWatcher.EnableRaisingEvents = true;

            Console.Read();
        }     

        static void FileSystemWatcher_Created(object sender, FileSystemEventArgs e)
        {           
                string SourceFolderPath = "D:\\SourcePath";
                string DestinationFolderPath = "D:\\DestinationPath";

                try
                {
                    // DO SOMETING LIKE MOVE, COPY, ETC
                    File.Copy(e.FullPath, DestinationFolderPath + @"\" + e.Name);
                }
                catch
                {
                }          
        }
}

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

class Program
{
    static string IsSameFile = string.Empty;  // USE STATIC FOR TRACKING

    static void Main(string[] args)
    {
         string SourceFolderPath = "D:\\SourcePath";
        string DestinationFolderPath = "D:\\DestinationPath";
        FileSystemWatcher FileSystemWatcher = new FileSystemWatcher();
        FileSystemWatcher.Path = SourceFolderPath;
        FileSystemWatcher.IncludeSubdirectories = false;
        FileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite;          
        FileSystemWatcher.Filter = "*.txt";         
        FileSystemWatcher.Changed += FileSystemWatcher_Changed;
        FileSystemWatcher.EnableRaisingEvents = true;

        Console.Read();
    }     

    static void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
    {
        if (e.Name == IsSameFile)  //SKIPS ON MULTIPLE TRIGGERS
        {
            return;
        }
        else
        {
            string SourceFolderPath = "D:\\SourcePath";
            string DestinationFolderPath = "D:\\DestinationPath";

            try
            {
                // DO SOMETING LIKE MOVE, COPY, ETC
                File.Copy(e.FullPath, DestinationFolderPath + @"\" + e.Name);
            }
            catch
            {
            }
        }
        IsSameFile = e.Name;
    }
}

Это обходное решение для этой проблемы множественного запускающего события.

Марк Макнейл Бикио
источник
0

Я бы сказал, использовать опрос, особенно в сценарии TDD, так как гораздо проще смоделировать / заглушить наличие файлов или иным образом при запуске события опроса, чем полагаться на более «неконтролируемое» событие fsw. + к тому, что он работал над множеством приложений, которые страдали от ошибок fsw.

user2819502
источник