2010-12-27 20 views
5

Ho un'applicazione che avvia altre applicazioni, quindi attende che creino un file di dati specifico (guarda un'applicazione alla volta). Ogni volta che un'applicazione viene avviata, controlla una directory specifica per creare un file specifico. Sto usando FileSystemWatcher per farlo (impostarlo sulla directory, quindi filtrare il nome file corretto). Funziona alla grande la prima volta (sempre), ma la seconda applicazione lanciata non accende mai l'evento. L'unico modo in cui sembra attivare l'evento è se inserisco un punto di interruzione nel gestore eventi o se ho un comando Thread.Sleep nel gestore eventi. Mi sembra molto strano ... ci sono delle condizioni di gara di cui non sono a conoscenza? Ecco il codice. Si noti che ho un Thread.Sleep (500). Con questa linea il codice funziona sempre. Senza di esso fallirà. Non mi sento davvero a mio agio affidandomi a un comando del sonno. Non sono sicuro di quale condizione causerà che non funzioni altrettanto bene.FileSystemWatcher - evento che non si attiva la seconda volta

public static void watchFiles(string path) 
    { 
     FileSystemWatcher watcher = new FileSystemWatcher(); 
     watcher.Path = path; 
     watcher.Created += new FileSystemEventHandler(watcher_Handler); 
     watcher.EnableRaisingEvents = true; 
    } 

    public static void watcher_Handler(object sender, FileSystemEventArgs e) 
    { 
     //Hack - the sleep allows the second and third application to be caught by this event 
     Thread.Sleep(500); 

     switch (e.ChangeType.ToString()) 
     { 
      case "Changed": 
       break; 
      case "Deleted": 
       break; 
      case "Created": 
       if (e.Name == "log.dat") 
       { 
        parseDataFile(); 
        moveHTMLtoLMS(); 

       } 
       break; 
      default: 
       break; 
     } 
    } 

Qualcuno sa il motivo per cui ho bisogno di avere quel sonno (o break-point) per ottenere il codice di lavorare una seconda volta?

+0

questo codice mi sembra a posto. – Simone

+5

nota: non è necessario utilizzare 'e.ChangeType.ToString()' nello switch, basta accendere 'e.ChangeType' e creare i casi' ChangeType.XXX'. Ciò lo rende fortemente digitato e meno soggetto a errori. – Femaref

+0

L'osservatore del filesystem sembra avere molti avvertimenti. http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.oncreated.aspx Detto questo, sei sicuro che i vari osservatori non stiano guardando la stessa directory? – NotMe

risposta

1

Secondo la documentazione della classe System.IO.FileSystemWatcher:

Il sistema operativo Windows avvisa il componente di modifiche apportate ai file in un buffer creato dal FileSystemWatcher. Se ci sono molti cambiamenti in poco tempo, il buffer può traboccare. Ciò fa sì che il componente perda traccia delle modifiche nella directory e fornirà solo una notifica generale. Aumentare la dimensione del buffer con la proprietà InternalBufferSize è costoso, poiché proviene da una memoria non di paging che non può essere scambiata su disco, quindi mantenere il buffer piccolo ma sufficientemente grande da non perdere eventi di modifica dei file. Per evitare un overflow del buffer, utilizzare le proprietà NotifyFilter e IncludeSubdirectories in modo da poter filtrare le notifiche di modifica indesiderate.

Potrebbe essere che l'evento non sia stato consumato abbastanza velocemente e il buffer interno non è abbastanza grande da gestire tutte le notifiche. Per impostazione predefinita, l'osservatore gestisce le notifiche FileName, DirectoryName, LastWrite eppure si utilizzano solo eventi di creazione (file e directory). Le tue applicazioni funzionano in rapida successione? Proverò a inserire un ritardo tra le invocazioni delle applicazioni (anziché il gestore di eventi), utilizzare filtri più specifici (solo la notifica FileName o guardare solo i file di registro utilizzando la proprietà Filter), aumentare la dimensione del buffer interno o qualsiasi combinazione di cui sopra. Penso che dovrebbe risolvere il tuo problema.

+1

Le altre applicazioni non sono in esecuzione in rapida successione. Posso aspettare qualche secondo o qualche minuto tra l'avvio di diverse applicazioni con gli stessi risultati. – cwo

+0

@cwo: Allora potresti essere in grado di farla franca lasciando i ritardi se hai provato le altre cose che ho menzionato. –

0

Si sta ascoltando solo un evento "Creato". È necessario ascoltare anche tutti gli altri - OnChanged, OnDeleted - http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.aspx

MODIFICA: la maggior parte dei programmi non crea il file "Crea" quando esiste già. È possibile utilizzare FileMon (ora Process Monitor - http://technet.microsoft.com/en-us/sysinternals/bb896645) per vedere quali operazioni eseguono ciascun programma con il proprio file.

+0

L'evento creato è l'unico a cui sono interessato. Gli altri casi nell'istruzione switch erano lì solo per testare il filesystemwatcher all'inizio. Quando viene creato il file, devo analizzarlo. Il modo in cui funziona i file non saranno mai modificati, cancellati o rinominati (o se sono a me non interessa). – cwo

+0

Prova a utilizzare Process Monitor per verificare le tue ipotesi - sospetto che non ci siano operazioni "Crea" eseguite da altri programmi ... O almeno saprai per certo che il problema è con il tuo codice, non con le notifiche. –

+0

Ho verificato che il file è stato creato nella posizione corretta. Sto usando Process Explorer. Ma posso anche solo aprire la directory in questione e vedere che il file è in fase di creazione. – cwo

0

Sto affrontando lo stesso identico problema qui (con Windows XP in esecuzione). Il tuo hack risolve il problema. Vorrei aggiungere alcune note che potrebbero essere rilevanti.

Nel mio caso il nome file è sempre lo stesso: C: \ blah.txt viene creato, cancellato, creato e così via. Inoltre, sto usando un trucco per nascondere la mia domanda:

Integrator.StartMonitor(); // Start the file monitor! 

Form f = new Form(); 
f.ShowInTaskbar = false; 
f.ShowIcon = false; 
f.StartPosition = FormStartPosition.Manual; 
f.Location = new Point(-32000, -32000); 

f.Show(); 
f.Hide(); 

Application.Run(); 

mio watcher file funziona in modalità debug o quando aggiungo il sonno-hack del tuo. Sicuramente sembra un bug nello FileSystemWatcher.

1
public static void watchFiles(string path) 
{ 
    FileSystemWatcher watcher = new FileSystemWatcher(); 
    watcher.Path = path; 
    watcher.Created += new FileSystemEventHandler(watcher_Handler); 
    watcher.EnableRaisingEvents = true; 
} 

La variabile watcher è idonea per la garbage collection alla fine di questo metodo. Invece di essere una variabile locale, rendilo un membro di livello come tale:

private static FileSystemWatcher watcher; 

public static void watchFiles(string path) 
{ 
    if (watcher != null) 
    { 
     watcher.EnableRaisingEvents = false; 
     watcher.Created -= new FileSystemEventHandler(watcher_Handler); 
    } 

    watcher = new FileSystemWatcher(); 
    watcher.Path = path; 
    watcher.Created += new FileSystemEventHandler(watcher_Handler); 
    watcher.EnableRaisingEvents = true; 
} 
Problemi correlati