Проверка файлов на наличие модификаций

Что я делаю

Я работаю над веб-сервисом, который копирует файлы из одного места в другое. Файлы обновляются (размер должен увеличиваться каждые 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);
}
Другие вопросы по тегам