FileSystemWatcher vs polling per controllare le modifiche ai file


152

Devo installare un'applicazione che controlla la creazione di file in una directory, sia localmente che su un'unità di rete.

Il FileSystemWatcherpolling o il polling su un timer sarebbe l'opzione migliore. Ho usato entrambi i metodi in passato, ma non ampiamente.

Quali problemi (prestazioni, affidabilità ecc.) Ci sono con entrambi i metodi?


3
FileSystemWatcher è un'astrazione che perde e non può essere invocata per nient'altro che i casi più elementari. Vedi qui: stackoverflow.com/a/22768610/129130
Stein Åsmul

1
Desideri aggiungere un collegamento per riferimento a questa risposta di Raymond Chen (esperto Microsoft) sull'argomento dell'affidabilità di FileSystemWatcher . E il suo blog: The Old New Thing (cercare FileSystemWatcher per esempio).
Stein Åsmul l'

Risposte:


105

Ho visto il watcher del file system fallire negli ambienti di produzione e test. Ora lo considero una comodità, ma non lo considero affidabile. Il mio modello è stato quello di controllare le modifiche con il watcher del file system, ma occasionalmente il sondaggio per rilevare le modifiche ai file mancanti.

Modifica: se hai un'interfaccia utente, puoi anche dare al tuo utente la possibilità di "aggiornare" le modifiche invece del polling. Vorrei combinare questo con un osservatore del file system.


11
Ho visto se anche cadere. La soluzione che abbiamo usato è quella di avvolgere la nostra classe, in cui la classe wrapper utilizza ANCHE un timer per verificare che l'osservatore stia ancora andando.
Joel Coehoorn,

Facciamo qualcosa di simile: una volta elaborato il file passato nell'evento FileCreated, eseguiamo un controllo manuale per eventuali altri nuovi file prima di tornare. Questo sembra mitigare qualsiasi problema che si verifichi quando arrivano molti file contemporaneamente.
John Sibly,

4
Credo che l'abbiamo testato in XP e Server 2003 su una directory locale e una condivisione di file e che avessimo macchine XP sul campo. Abbiamo riscontrato problemi con la directory locale e la condivisione file. Una delle probabili cause che abbiamo scoperto è stata la copia / creazione di molti file in un breve lasso di tempo nella directory.
Jason Jackson,

5
Non è molto costruttivo né professionale affermare semplicemente "un giorno ho visto un fantasma". Sembra che le persone in fondo al thread, menzionando il documento msdn sui sovraccarichi del buffer non di pagina, possano spiegare i tuoi problemi. Hai provato ad usare l'approccio di Brent?
v.oddou,

4
Ho appena comprato un sensore di gas su Amazon e mi ha stupito di quante persone hanno detto che non funzionava, quando ovviamente non lo hanno calibrato correttamente o non sapevano nemmeno della calibrazione ... FileSystemWatcher ha conosciuto limiti con traffico elevato da la sua dimensione del buffer. Quasi garantito che questo è il motivo del "fallimento". Questo è prontamente spiegato nella documentazione e ci sono soluzioni che forniscono un funzionamento molto affidabile (come pubblicato di seguito). Questa non è una buona risposta per dire "errr, qualcosa non ha funzionato una volta, non so perché ... nessuno dovrebbe fare affidamento su di esso".
Il

60

Il problema più grande che ho avuto è la mancanza di file quando il buffer si riempie. Facile da correggere: basta aumentare il buffer. Ricorda che contiene i nomi dei file e gli eventi, quindi aumentalo alla quantità prevista di file (prova ed errore). Usa una memoria che non può essere paginata, quindi potrebbe forzare altri processi alla pagina se la memoria si esaurisce.

Ecco l'articolo MSDN sul buffer: FileSystemWatcher .. ::. InternalBufferSize Proprietà

Per MSDN:

L'aumento della dimensione del buffer è costoso, poiché proviene da memoria non paginata che non può essere scambiata su disco, quindi mantenere il buffer il più piccolo possibile. Per evitare un overflow del buffer, utilizzare le proprietà NotifyFilter e IncludeSubdirectories per filtrare le notifiche di modifica indesiderate.

Usiamo 16 MB a causa di un grande lotto previsto contemporaneamente. Funziona bene e non perde mai un file.

Leggiamo anche tutti i file prima di iniziare a elaborare anche uno ... prendere i nomi dei file memorizzati nella cache in modo sicuro (nel nostro caso, in una tabella del database) quindi elaborarli.

Per problemi di blocco dei file ho generato un processo che attende lo sblocco del file in attesa di un secondo, quindi due, quindi quattro, eccetera. Non facciamo mai sondaggi. Questo è stato in produzione senza errori per circa due anni.


12
Buffer overflow? Oh, vuoi dire overflow dello stack.
TheFlash,

1
A partire da .NET 3.5: "È possibile impostare il buffer su 4 KB o più, ma non deve superare 64 KB"
brad

9
Come stai usando 16 MB se il buffer interno massimo per FileSystemWatcher è 64 KB?
BK,

1
@ Jarvis, un buffer è una posizione di archiviazione temperata configurata per contenere le informazioni mentre vengono trasmesse fino a quando non possono essere elaborate, questo di solito significa un FIFO o una coda in quanto si desidera gestire le richieste nell'ordine in cui arrivano, tuttavia in alcuni processi come la ricorsione nei programmi viene utilizzata una struttura FILO o Stack, in questo caso ci riferiamo sicuramente al buffer della coda eventi e non ai programmi che chiamano buffer stack
MikeT

1
petermeinl.wordpress.com/2015/05/18/tamed-filesystemwatcher Questo post condivide i wrapper robusti attorno al FileSystemWatcher (FSW) standard che risolvono i problemi che si verificano comunemente quando lo si utilizza per monitorare il file system nelle applicazioni del mondo reale.
Kiquenet,

35

L' FileSystemWatcherpuò anche perdere modifiche durante occupato volte, se il numero di modifiche in coda overflow del buffer fornito. Questa non è una limitazione della classe .NET in sé, ma dell'infrastruttura Win32 sottostante. Nella nostra esperienza, il modo migliore per ridurre al minimo questo problema è rimuovere le notifiche il più rapidamente possibile e gestirle su un altro thread.

Come menzionato da @ChillTemp sopra, l'osservatore potrebbe non funzionare su condivisioni non Windows. Ad esempio, non funzionerà affatto sulle unità Novell montate.

Concordo sul fatto che un buon compromesso sia fare un sondaggio occasionale per raccogliere eventuali modifiche perse.


4
Il watcher del filesystem può iniziare a raccogliere molti eventi in rapida successione. Se non puoi eseguire il gestore dell'evento almeno con la stessa velocità con cui vengono sparati, alla fine il gestore inizierà a far cadere gli eventi sul pavimento e ti mancheranno le cose.
Brent Rockwood,

17

Inoltre, il watcher del file system non è affidabile per le condivisioni di file. In particolare se la condivisione file è ospitata su un server non Windows. FSW non dovrebbe essere usato per nulla di critico. O dovrebbe essere usato con un sondaggio occasionale per verificare che non abbia perso nulla.


3
Microsoft ha riconosciuto che non è affidabile per le condivisioni di file non Windows? Sicuramente stiamo vivendo questa prima mano dal passaggio da una condivisione Windows a una condivisione SMB basata su Linux.
Sean,

1
Non che ne sia consapevole. E sono sicuro che sarebbe semplicemente un gioco di colpa tra i diversi fornitori.
chilltemp,

1
Abbiamo riscontrato problemi con il watcher del file system su unità mappate. Se la mappa si disconnette e quindi si riconnette, il watcher dei file non genera più modifiche. Facilmente risolto ma ancora uno sciopero contro l'IMHO del file system watcher.
Richard Dorman,

11

Personalmente, ho usato il FileSystemWatchersistema di produzione e ha funzionato bene. Negli ultimi 6 mesi, non ha avuto un singolo singhiozzo in esecuzione 24x7. Sta monitorando una singola cartella locale (che è condivisa). Abbiamo un numero relativamente piccolo di operazioni sui file che deve gestire (10 eventi generati al giorno). Non è qualcosa di cui mi debba mai preoccupare. Lo userei di nuovo se dovessi rifare la decisione.


7

Attualmente uso il FileSystemWatcherfile su XML che viene aggiornato in media ogni 100 millisecondi.

Ho scoperto che fintanto che FileSystemWatcherè configurato correttamente non dovresti mai avere problemi con i file locali .

Non ho esperienza sulla visualizzazione di file remoti e condivisioni non Windows.

Considererei ridondante il polling del file e non valga il sovraccarico a meno che tu non abbia intrinsecamente diffidenza FileSystemWatchero non abbia sperimentato direttamente i limiti elencati da tutti gli altri qui (condivisioni non Windows e controllo remoto dei file).


5

Andrei con il polling.

Problemi di rete causano l' FileSystemWatcheraffidabilità (anche in caso di sovraccarico dell'evento di errore).


5

Ho riscontrato problemi con FileSystemWatcherle condivisioni di rete. Se ti trovi in ​​un ambiente Windows puro, potrebbe non essere un problema, ma stavo guardando una condivisione NFS e poiché NFS è senza stato, non c'è mai stata una notifica quando il file che stavo guardando è cambiato.


Ho riscontrato lo stesso problema, ma per me è stato inaspettato poiché FileSystemWatcher si trovava sullo stesso server Windows che condivide la cartella utilizzando NFS. il fatto di condividere una cartella con NFS fa sì che il filesystemwatcher non veda i file creati usando la condivisione in remoto (cioè da un Linux che mappa la condivisione) mentre se scrivo un file sulla stessa cartella sotto monitoraggio, viene attivato il filesystemwatcher. sembra che il server NFS scriva i file usando un livello inferiore e il livello API che attiva il filesystemwatcher non è attivo, qualcuno ha più informazioni?
Mosè Bottacini,

3

Ho avuto alcuni grossi problemi con FSW su unità di rete: l'eliminazione di un file ha sempre generato l'evento di errore, mai l'evento eliminato. Non ho trovato una soluzione, quindi evito il FSW e utilizzo il polling.

D'altra parte, gli eventi di creazione hanno funzionato bene, quindi se devi solo guardare per la creazione di file, puoi scegliere FSW.

Inoltre, non ho avuto alcun problema con le cartelle locali, indipendentemente dal fatto che siano condivise o meno.


3

Tornando dal metodo dell'evento il più rapidamente possibile, usando un altro thread, ho risolto il problema per me:

private void Watcher_Created(object sender, FileSystemEventArgs e)
{
    Task.Run(() => MySubmit(e.FullPath));
}

2

Utilizzando sia FSW e polling è uno spreco di tempo e risorse, a mio parere, e mi sorprende che gli sviluppatori esperti suggeriscono che. Se è necessario utilizzare il polling per verificare la presenza di "errori FSW", è possibile, naturalmente, scartare completamente FSW e utilizzare solo il polling.

Attualmente sto cercando di decidere se usare FSW o il polling per un progetto che sviluppo. Leggendo le risposte, è ovvio che ci sono casi in cui FSW copre perfettamente le esigenze, mentre altre volte è necessario il polling. Sfortunatamente, nessuna risposta ha effettivamente affrontato la differenza di prestazioni (se presente), solo con i problemi di "affidabilità". C'è qualcuno che può rispondere a quella parte della domanda?

EDIT: il punto di nmclean per la validità dell'utilizzo sia di FSW che del polling (puoi leggere la discussione nei commenti, se sei interessato) sembra essere una spiegazione molto razionale perché ci possono essere situazioni in cui l'uso sia di un FSW che del polling è efficiente. Grazie per far luce su questo per me (e chiunque altro abbia la stessa opinione), nmclean .


1
Cosa succede se si desidera rispondere alle modifiche ai file il più rapidamente possibile? Ad esempio, se esegui il polling una volta al minuto, potresti avere un ritardo di almeno 1 minuto tra la modifica di un file e l'applicazione che rileva la modifica. L'evento FSW sarebbe presumibilmente innescato molto prima. Quindi, usando entrambi, gestisci gli eventi con il minor ritardo possibile, ma raccogli anche gli eventi persi, se ce ne sono.
Rom99,

@ rom99 Esattamente il mio punto. Se l'FSW non è affidabile nei casi in cui sia necessaria una risposta rapida, non ha senso utilizzarlo, poiché si avranno casi in cui non ci sarà una risposta rapida, pertanto l'applicazione non sarà affidabile. Il polling a intervalli più brevi, in un thread, sarebbe quello che devi fare. Facendo entrambi , significa avere una tolleranza nei tempi di risposta coperti dal polling, quindi perché non utilizzare solo il polling?
ThunderGr

5
@ThunderGr "pertanto, l'applicazione non sarà affidabile." - In molti casi, la velocità non è un prerequisito per l'affidabilità. Il lavoro deve essere completato, ma può aspettare un po '. Se combiniamo polling lento e affidabile con FSW veloce e inaffidabile , otteniamo un'applicazione sempre affidabile e talvolta veloce, che è meglio di affidabile e mai veloce. Possiamo rimuovere FSW e ottenere lo stesso tempo di risposta massimo eseguendo il polling costante, ma questo è a spese della reattività del resto dell'applicazione, quindi dovrebbe essere fatto solo se è assolutamente necessaria una risposta immediata.
nmclean,

2
Ora, perché quanto sopra è un argomento scarso? Perché, sebbene abbiamo ancora bisogno dell'accesso al disco, ne abbiamo meno bisogno . Allo stesso modo, puoi effettuare il polling di meno. Solo perché controlliamo ancora tutti i file non significa che il carico di lavoro sia lo stesso. La tua affermazione "il polling è costoso in termini di tempo della CPU con FSW o no" è falsa . Scaricando la preoccupazione di "immediatezza" su FSW, possiamo cambiare il polling in un compito inattivo, a bassa priorità, in modo tale che la frenesia dell'applicazione in qualsiasi momento sia drasticamente ridotta pur fornendo il "trattamento" di immediatezza. Semplicemente non è possibile raggiungere lo stesso equilibrio con il solo polling.
nmclean,

9
@nmclean Grazie per aver dedicato il tempo e l'energia per chiarire questo come hai fatto. Quando la metti in questo modo, ha sicuramente molto più senso. Proprio come ci sono volte in cui una cache non è adatta al tuo problema specifico, quindi l'FSW (quando si rivela inaffidabile) potrebbe non essere adatto. Si scopre che hai sempre avuto ragione. Mi dispiace che ci sia voluto così tanto tempo per ottenerlo.
ThunderGr

1

Soluzione funzionante per lavorare con create event anziché change

Anche per copiare, tagliare, incollare, spostare.

class Program
{        

        static void Main(string[] args)
        {
            string SourceFolderPath = "D:\\SourcePath";
            string DestinationFolderPath = "D:\\DestinationPath";
            FileSystemWatcher FileSystemWatcher = new FileSystemWatcher();
            FileSystemWatcher.Path = SourceFolderPath;
            FileSystemWatcher.IncludeSubdirectories = false;
            FileSystemWatcher.NotifyFilter = NotifyFilters.FileName;   // ON FILE NAME FILTER       
            FileSystemWatcher.Filter = "*.txt";         
             FileSystemWatcher.Created +=FileSystemWatcher_Created; // TRIGGERED ONLY FOR FILE GOT CREATED  BY COPY, CUT PASTE, MOVE  
            FileSystemWatcher.EnableRaisingEvents = true;

            Console.Read();
        }     

        static void FileSystemWatcher_Created(object sender, FileSystemEventArgs e)
        {           
                string SourceFolderPath = "D:\\SourcePath";
                string DestinationFolderPath = "D:\\DestinationPath";

                try
                {
                    // DO SOMETING LIKE MOVE, COPY, ETC
                    File.Copy(e.FullPath, DestinationFolderPath + @"\" + e.Name);
                }
                catch
                {
                }          
        }
}

Soluzione per questo osservatore di file mentre l'evento di modifica dell'attributo del file utilizza l'archiviazione statica

class Program
{
    static string IsSameFile = string.Empty;  // USE STATIC FOR TRACKING

    static void Main(string[] args)
    {
         string SourceFolderPath = "D:\\SourcePath";
        string DestinationFolderPath = "D:\\DestinationPath";
        FileSystemWatcher FileSystemWatcher = new FileSystemWatcher();
        FileSystemWatcher.Path = SourceFolderPath;
        FileSystemWatcher.IncludeSubdirectories = false;
        FileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite;          
        FileSystemWatcher.Filter = "*.txt";         
        FileSystemWatcher.Changed += FileSystemWatcher_Changed;
        FileSystemWatcher.EnableRaisingEvents = true;

        Console.Read();
    }     

    static void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
    {
        if (e.Name == IsSameFile)  //SKIPS ON MULTIPLE TRIGGERS
        {
            return;
        }
        else
        {
            string SourceFolderPath = "D:\\SourcePath";
            string DestinationFolderPath = "D:\\DestinationPath";

            try
            {
                // DO SOMETING LIKE MOVE, COPY, ETC
                File.Copy(e.FullPath, DestinationFolderPath + @"\" + e.Name);
            }
            catch
            {
            }
        }
        IsSameFile = e.Name;
    }
}

Questa è una soluzione alternativa per questo problema di evento scatenante multiplo.


0

Direi usare il polling, specialmente in uno scenario TDD, poiché è molto più facile deridere / stub la presenza di file o altrimenti quando viene attivato l'evento di polling piuttosto che fare affidamento sull'evento fsw più "incontrollato". + a quello di aver lavorato su una serie di app afflitte da errori fsw.

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.