Использование 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 копирует его откуда-то), но для завершения этого процесса потребуется несколько минут. Событие возникает во время создания, и вам нужно дождаться, пока файл будет готов к копированию.

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

nvoigt
источник
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.
}
user1912419
источник
18
watcherпеременная остается активной (а не сборщиком мусора), потому что он подписался на событие Changed.
adospace
1
Я считаю, что это на самом деле потому, что для EnableRaisingEvents установлено значение true. Я не думаю, что статус обработчиков событий участников имеет отношение к сборке мусора. Я думаю, что EnableRaisingEvents имеет, как я бы сказал, особое поведение в этом случае.
Матиас Гриони