Проверка файлов на наличие модификаций
Что я делаю
Я работаю над веб-сервисом, который копирует файлы из одного места в другое. Файлы обновляются (размер должен увеличиваться каждые 3 секунды, так как добавлен текст).
1-й вариант:
Я проверяю каждые 10 секунд, изменяется ли какой-либо из файлов (они изменяются каждые 5 секунд приблизительно), чтобы я мог скопировать (и перезаписать) их в конечный пункт назначения. Я использую код, который сравнивает время последнего редактирования файла с фактическим временем - некоторое количество времени (1 минута).
DateTime lastEditTime = new DateTime();
lastEditTime = File.GetLastWriteTime(myFile);
if (lastEditTime > DateTime.Now.AddMinutes(-1))
{
File.Copy(myFile, newFileName, true);
}
Но я думаю, что это довольно плохой подход, поскольку может быть какое-то время или что-то подобное, и я не получу некоторые изменения.
2-й вариант
Я мог бы проверить размеры файлов (возможно, используя свойство FileInfo.Length) каждого файла в исходном каталоге и сравнить их с теми, которые находятся в конечном месте назначения. Это тоже должно быть хорошо, так как размеры файлов должны только увеличиваться, так как добавляется только текст.
3-й вариант
Я читаю много людей, которые рекомендуют FileSystemWatcher, но я не хочу пропустить некоторые изменения, которые могут произойти - по крайней мере, я читал об этом в других вопросах SO (см. /questions/44457986/filesystemwatcher-protiv-oprosa-chtobyi-nablyudat-za-izmeneniyami-fajla/44458098#44458098).
Какой у меня вопрос?
Что лучше всего знать, если какой-либо файл был изменен (если файл в источнике отличается от файла в конечном месте назначения) в последние x минут или секунд, потому что я не хочу копировать все, потому что может быть много файлов. Под лучшим вариантом я подразумеваю: быстрее ли сравнивать размеры каждого файла или сравнивать File.GetLastWriteTime(myFile)
с реальным временем - некоторое время. Во втором случае также возникает вопрос: насколько большим должен быть промежуток времени? Если я установлю большой промежуток времени, я, вероятно, скопирую больше файлов, чем мне нужно на самом деле, но если я укажу его слишком низким, я могу пропустить некоторые изменения.
Если у вас есть лучшие варианты, не стесняйтесь поделиться ими со мной!
1 ответ
Хотя вы уже упоминали об этом в своем варианте 3, я все же думаю, что стоит попробовать его с классом FileSystemWatcher. Насколько я вас понял, вы еще этого не сделали, верно?
Хотя это правда, что наблюдатель может потерять какое-то событие в конфигурации по умолчанию, вы все равно можете заставить его работать надежно, если вы внесете некоторые изменения.
Взгляните на раздел "Замечания" в документации (выделено мной):
Операционная система Windows уведомляет ваш компонент об изменениях файлов в буфере, созданном FileSystemWatcher. Если за короткое время произойдет много изменений, буфер может переполниться. Это приводит к тому, что компонент теряет отслеживание изменений в каталоге, и он будет предоставлять только общее уведомление. Увеличение размера буфера с помощью свойства InternalBufferSize является дорогостоящим, так как оно поступает из невыгружаемой памяти, которую нельзя выгружать на диск, поэтому сохраняйте буфер как небольшой, но достаточно большой, чтобы не пропустить какие-либо события изменения файла. Чтобы избежать переполнения буфера, используйте свойства NotifyFilter и IncludeSubdirectories, чтобы можно было отфильтровывать нежелательные уведомления об изменениях.
Что вы можете сделать, чтобы это работало надежно:
Обратите внимание, что FileSystemWatcher может пропустить событие при превышении размера буфера. Чтобы избежать пропущенных событий, следуйте этим рекомендациям:
- Увеличьте размер буфера, установив свойство InternalBufferSize.
- Избегайте просмотра файлов с длинными именами файлов, потому что длинное имя файла способствует заполнению буфера. Попробуйте переименовать эти файлы, используя более короткие имена.
- Сделайте ваш код обработки событий как можно короче.
Например, пользователь Nomix говорит, что он увеличил размер буфера (свойство InternalBufferSize) до 16 МБ и никогда не имел проблем с FileSystemWatcher
класс (ТАК сообщение здесь.) И я могу подтвердить это с проектом в моей компании, который работает хорошо в течение многих лет, так как мы узнали о буфере.
Инициализация объекта может выглядеть следующим образом:
private void InitWatcher()
{
// Create a new FileSystemWatcher and set its properties.
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = "Your path to watch";
// You only want to watch a single folder
watcher.IncludeSubdirectories = false;
// You mentioned both LastWrite and Size
// You can combine them or just watch for only a specific property
// Simply configure it to your needs
watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size
// Only watch text files.
watcher.Filter = "*.txt";
// Add event handlers, omit those you are not interested in
watcher.Changed += new FileSystemEventHandler(OnChanged);
// Begin watching.
watcher.EnableRaisingEvents = true;
}
Затем вы можете подписаться на те события, которые вас интересуют, например, событие Changed, и реагировать на него так же просто, как:
private static void OnChanged(object source, FileSystemEventArgs e)
{
File.Copy(e.FullPath, newFileName, true);
}