FileSystemWatcher против опроса, чтобы наблюдать за изменениями файла
Мне нужно настроить приложение, которое следит за файлами, создаваемыми в каталоге, как локально, так и на сетевом диске.
Будет ли FileSystemWatcher
или опрос по таймеру будет лучшим вариантом. Я использовал оба метода в прошлом, но не широко.
Какие проблемы (производительность, надежность и т. Д.) Существуют с любым из этих методов?
13 ответов
Я видел сбой наблюдателя файловой системы в производственных и тестовых средах. Сейчас я считаю это удобством, но я не считаю это надежным. Мой паттерн состоял в том, чтобы следить за изменениями с помощью наблюдателя файловой системы, но время от времени опрашивать, чтобы отследить отсутствующие изменения файла.
Изменить: если у вас есть пользовательский интерфейс, вы также можете дать своему пользователю возможность "обновлять" изменения вместо опроса. Я бы сочетал это с наблюдателем файловой системы.
Самая большая проблема, с которой я столкнулся, - это отсутствие файлов при заполнении буфера. Легко исправить, просто увеличьте буфер. Помните, что он содержит имена файлов и события, поэтому увеличьте его до ожидаемого количества файлов (методом проб и ошибок). Он использует память, которая не может быть выгружена из памяти, поэтому он может заставить другие процессы отображать страницы, если памяти становится мало.
Вот статья MSDN о буфере: FileSystemWatcher..::. InternalBufferSize Свойство
По MSDN:
Увеличение размера буфера обходится дорого, так как оно исходит из не выгружаемой памяти, которую нельзя выгрузить на диск, поэтому размер буфера должен быть как можно меньше. Чтобы избежать переполнения буфера, используйте свойства NotifyFilter и IncludeSubdirectories для фильтрации нежелательных уведомлений об изменениях.
Мы используем 16 МБ из-за большой партии, ожидаемой за один раз. Работает нормально и никогда не пропускает файл.
Мы также читаем все файлы перед тем, как начинать обрабатывать хотя бы один файл... надежно кэшируем имена файлов (в нашем случае, в таблицу базы данных), а затем обрабатываем их.
Для проблем с блокировкой файлов я запускаю процесс, который ждет, пока файл будет разблокирован, и ждет одну секунду, затем две, затем четыре и так далее. Мы никогда не опрашиваем. Это было в производстве без ошибок около двух лет.
FileSystemWatcher
может также пропустить изменения во время занятости, если число изменений в очереди переполняет предоставленный буфер. Это не ограничение класса.NET как такового, а базовой инфраструктуры Win32. По нашему опыту, лучший способ минимизировать эту проблему - это как можно быстрее убрать уведомления из очереди и обработать их в другом потоке.
Как упомянуто выше @ChillTemp, наблюдатель может не работать с общими папками, отличными от Windows. Например, он не будет работать на подключенных дисках Novell.
Я согласен с тем, что хорошим компромиссом является проведение периодического опроса для выявления любых пропущенных изменений.
Также обратите внимание, что наблюдатель файловой системы не надежен на общих файловых ресурсах. Особенно, если общий файловый ресурс размещен на сервере, отличном от Windows. FSW не должен использоваться для чего-то критического. Или следует использовать время от времени опрос, чтобы убедиться, что он ничего не пропустил.
Лично я использовал FileSystemWatcher
на производственной системе, и она работала нормально. За последние 6 месяцев не было ни одного сбоя 24x7. Он контролирует одну локальную папку (которая является общей). У нас есть относительно небольшое количество файловых операций, которые он должен обрабатывать (10 событий в день). Это не то, о чем мне когда-либо приходилось беспокоиться. Я бы использовал это снова, если бы мне пришлось переделать решение.
Я столкнулся с проблемой при использовании FileSystemWatcher
на сетевых ресурсах. Если вы находитесь в чистой среде Windows, это может не быть проблемой, но я наблюдал за общим ресурсом NFS, и, поскольку NFS не имеет состояния, никогда не было уведомлений о том, что файл, который я смотрел, изменился.
В настоящее время я использую FileSystemWatcher
в XML-файле обновляется в среднем каждые 100 миллисекунд.
Я обнаружил, что до тех пор, пока FileSystemWatcher
правильно настроен, у вас никогда не должно быть проблем с локальными файлами.
У меня нет опыта в удаленном просмотре файлов и не в Windows.
Я считаю, что опрос файла является избыточным и не стоит накладных расходов, если вы по своей сути не доверяете FileSystemWatcher
или непосредственно испытали ограничения, которые все остальные здесь перечислили (не-общие ресурсы Windows и удаленный просмотр файлов).
Я бы пошел с опросом.
Проблемы с сетью вызывают FileSystemWatcher
быть ненадежным (даже при перегрузке события ошибки).
Возвращение из метода события как можно быстрее, используя другой поток, решило проблему для меня:
private void Watcher_Created(object sender, FileSystemEventArgs e)
{
Task.Run(() => MySubmit(e.FullPath));
}
У меня были большие проблемы с FSW на сетевых дисках: удаление файла всегда вызывало событие ошибки, а не удаление. Я не нашел решения, поэтому я теперь избегаю FSW и использую опрос.
С другой стороны, события создания работали нормально, поэтому, если вам нужно только следить за созданием файла, вы можете перейти на FSW.
Кроме того, у меня не было никаких проблем с локальными папками, независимо от того, были ли они общими или нет.
На мой взгляд, использование FSW и опросов - пустая трата времени и ресурсов, и я удивлен, что опытные разработчики предлагают это. Если вам нужно использовать опрос, чтобы проверить наличие "промахов FSW", то вы, естественно, можете вообще отказаться от FSW и использовать только опрос.
В настоящее время я пытаюсь решить, буду ли я использовать FSW или опрос для проекта, который я разрабатываю. Прочитав ответы, очевидно, что есть случаи, когда ЖСБ полностью удовлетворяет потребности, а в других случаях вам нужен опрос. К сожалению, ни один из ответов на самом деле не касался разницы в производительности (если она есть), только проблемы "надежности". Кто-нибудь может ответить на эту часть вопроса?
РЕДАКТИРОВАТЬ: точка зрения nmclean на правильность использования как ЖСБ, так и опросов (вы можете прочитать обсуждение в комментариях, если вам интересно) представляется весьма рациональным объяснением того, почему могут возникать ситуации, когда использование ЖСБ и опросов эффективный. Спасибо за то, что пролили свет на это для меня (и любого, кто придерживается того же мнения), nmclean.
Рабочее решение для работы с созданием события вместо изменения
Даже для копирования, вырезания, вставки, перемещения.
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;
}
}
Это обходное решение для этой проблемы многократного запуска события.
Я бы сказал, использовать опрос, особенно в сценарии TDD, так как гораздо проще смоделировать / заглушить наличие файлов или иным образом при запуске события опроса, чем полагаться на более "неконтролируемое" событие fsw. + к тому, что он работал над несколькими приложениями, которые страдали от ошибок fsw.