Utilisation de FileSystemWatcher pour surveiller un répertoire

101

J'utilise une application Windows Forms pour surveiller un répertoire et déplacer les fichiers déposés dans un autre répertoire.

Pour le moment, il copiera le fichier dans un autre répertoire, mais lorsqu'un autre fichier est ajouté, il se terminera simplement sans message d'erreur. Parfois, il copie deux fichiers avant de se terminer sur le troisième.

Est-ce parce que j'utilise une application Windows Form plutôt qu'une application console? Existe-t-il un moyen d'arrêter la fin du programme et de continuer à regarder le répertoire?

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();
}
fromager
la source

Réponses:

144

Le problème était les filtres de notification. Le programme essayait d'ouvrir un fichier en cours de copie. J'ai supprimé tous les filtres de notification à l'exception de 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;
}
fromager
la source
6
Bonjour, j'utilisais cette approche, mais lorsque je copie un fichier, l'événement est déclenché deux fois: une fois lorsque le fichier est créé vide (la copie commence) et une fois de plus lorsque la copie se termine. Comment éviter cet événement dupliqué, tout filtre capable de le gérer sans un contrôle personnalisé de cela?
dhalfageme
@dhalfageme Je vérifie sur les deux événements si quelque chose de significatif pour mon application apparaît dans le dossier.
Eftekhari le
30

Vous n'avez pas fourni le code de gestion des fichiers, mais je suppose que vous avez fait la même erreur que tout le monde fait lors de la première écriture d'une telle chose: l'événement Filewatcher sera déclenché dès que le fichier est créé. Cependant, la fin du fichier prendra un certain temps. Prenons par exemple une taille de fichier de 1 Go. Le fichier peut être créé par un autre programme (Explorer.exe le copiant de quelque part), mais cela prendra quelques minutes pour terminer ce processus. L'événement est déclenché au moment de la création et vous devez attendre que le fichier soit prêt à être copié.

Vous pouvez attendre qu'un fichier soit prêt en utilisant cette fonction dans une boucle.

nvoigt
la source
25

La raison peut être que watcher est déclaré comme variable locale à une méthode et qu'il est récupéré lorsque la méthode se termine. Vous devez le déclarer en tant que membre de la classe. Essayez ce qui suit:

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
la source
18
watchervariable est maintenue en vie (pas de récupération de place) car il s'est abonné à l'événement Changed.
adospace du
1
Je pense que c'est en fait parce que EnableRaisingEvents est défini sur true. Je ne pense pas que le statut des gestionnaires d'événements membres ait à voir avec le ramasse-miettes. Je pense que EnableRaisingEvents a, ce que je pourrais appeler favorablement, un comportement spécial dans ce cas.
Matias Grioni