Использование FileSystemWatcher для наблюдения за каталогом


101

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

На данный момент он скопирует файл в другой каталог, но при добавлении другого файла он просто закончится без сообщения об ошибке. Иногда он копирует два файла, прежде чем закончится третий.

Это потому, что я использую приложение Windows Form, а не консольное приложение? Есть ли способ остановить завершение программы и продолжить наблюдение за каталогом?

private void watch()
{
  this.watcher = new FileSystemWatcher();
  watcher.Path = path;
  watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
                         | NotifyFilters.FileName | NotifyFilters.DirectoryName;
  watcher.Filter = "*.*";
  watcher.Changed += OnChanged;
  watcher.EnableRaisingEvents = true;
}

private void OnChanged(object source, FileSystemEventArgs e)
{
  //Copies file to another directory.
}

public void Dispose()
{
  // avoiding resource leak
  watcher.Changed -= OnChanged;
  this.watcher.Dispose();
}

Ответы:


144

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

private void watch()
{
  FileSystemWatcher watcher = new FileSystemWatcher();
  watcher.Path = path;
  watcher.NotifyFilter = NotifyFilters.LastWrite;
  watcher.Filter = "*.*";
  watcher.Changed += new FileSystemEventHandler(OnChanged);
  watcher.EnableRaisingEvents = true;
}

6
Привет, я использовал этот подход, но когда я копирую файл, событие возникает дважды: один раз, когда файл создается пустым (начинается копирование), и еще раз, когда копирование завершается. Как избежать этого дублированного события, если какой-либо фильтр сможет его обработать без специального контроля?
dhalfageme

@dhalfageme Я проверяю оба события, появляется ли в папке что-нибудь значимое для моего приложения.
Эфтехари

30

Вы не предоставили код обработки файлов, но я предполагаю, что вы совершили ту же ошибку, что и все, когда впервые пишете такую ​​вещь: событие filewatcher будет вызвано, как только файл будет создан. Однако для завершения файла потребуется некоторое время. Возьмем, например, размер файла 1 ГБ. Файл может быть создан другой программой (Explorer.exe копирует его откуда-то), но для завершения этого процесса потребуется несколько минут. Событие возникает во время создания, и вам нужно дождаться, пока файл будет готов к копированию.

Вы можете дождаться готовности файла, используя эту функцию в цикле.


25

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

FileSystemWatcher watcher;

private void watch()
{
  watcher = new FileSystemWatcher();
  watcher.Path = path;
  watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
                         | NotifyFilters.FileName | NotifyFilters.DirectoryName;
  watcher.Filter = "*.*";
  watcher.Changed += new FileSystemEventHandler(OnChanged);
  watcher.EnableRaisingEvents = true;
}

private void OnChanged(object source, FileSystemEventArgs e)
{
  //Copies file to another directory.
}

18
watcherпеременная остается активной (а не сборщиком мусора), потому что он подписался на событие Changed.
adospace

1
Я считаю, что это на самом деле потому, что для EnableRaisingEvents установлено значение true. Я не думаю, что статус обработчиков событий участников имеет отношение к сборке мусора. Я думаю, что EnableRaisingEvents имеет, как я бы сказал, особое поведение в этом случае.
Матиас Гриони
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.