Utilizzo di FileSystemWatcher per monitorare una directory


101

Sto usando un'applicazione Windows Forms per monitorare una directory e spostare i file in essa contenuti in un'altra directory.

Al momento copierà il file in un'altra directory, ma quando viene aggiunto un altro file terminerà senza alcun messaggio di errore. A volte copia due file prima di terminare il terzo.

È perché sto usando un'applicazione Windows Form anziché un'app console? C'è un modo per interrompere la fine del programma e continuare a guardare la directory?

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

Risposte:


144

Il problema erano i filtri di notifica. Il programma stava tentando di aprire un file che stava ancora copiando. Ho rimosso tutti i filtri di notifica ad eccezione di 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
Ciao, stavo usando questo approccio ma quando copio un file l'evento viene generato due volte: una volta quando il file viene creato vuoto (la copia inizia) e un'altra volta quando la copia finisce. Come evitare questo evento duplicato, qualsiasi filtro in grado di gestirlo senza un controllo personalizzato di quello?
dhalfageme

@dhalfageme Controllo su entrambi gli eventi se nella cartella viene visualizzato qualcosa di significativo per la mia applicazione.
Eftekhari,

30

Non hai fornito il codice di gestione del file, ma presumo che tu abbia commesso lo stesso errore che fanno tutti quando scrivono per la prima volta una cosa del genere: l'evento filewatcher verrà generato non appena il file viene creato. Tuttavia, il completamento del file richiederà del tempo. Prendi una dimensione del file di 1 GB, ad esempio. Il file può essere creato da un altro programma (Explorer.exe copiandolo da qualche parte) ma ci vorranno minuti per completare il processo. L'evento viene generato al momento della creazione ed è necessario attendere che il file sia pronto per essere copiato.

È possibile attendere che un file sia pronto utilizzando questa funzione in un ciclo.


25

Il motivo potrebbe essere che watcher viene dichiarato come variabile locale per un metodo e viene raccolto in modo indesiderato al termine del metodo. Dovresti dichiararlo come membro della classe. Prova quanto segue:

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
watchervariabile viene mantenuta in vita (non raccolta in Garbage Collection) perché si è iscritto all'evento Changed.
adospace

1
Credo che in realtà sia perché EnableRaisingEvents è impostato su true. Non credo che lo stato dei gestori di eventi membri abbia a che fare con la garbage collection. Penso che EnableRaisingEvents abbia, quello che potrei chiamare favorevolmente, un comportamento speciale in questo caso.
Matias Grioni
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.