2010-02-09 11 views
10

Ho un filesystemwatcher che attiverà un evento quando un file viene modificato. Voglio leggere da quel file una volta che il blocco è stato rimosso. Al momento sto solo cercando di aprire il file una volta che l'evento è stato attivato, quando viene copiato un file di grandi dimensioni il blocco del file rimane attivo per un po 'dopo che gli eventi sono stati inviati, impedendo l'apertura del file per l'accesso in lettura.Attivatori di FileSystemWatcher per il flusso di file aperto

Qualche suggerimento?

risposta

6

Questo in realtà è un po 'un doozie, a meno che lo spazio del problema non sia cambiato in modo significativo dall'ultima volta che ho dovuto occuparmene.

Il modo più semplice è semplicemente provare ad aprire il file, catturare il risultato IOException e, se il file è bloccato, aggiungerlo a una coda per essere controllato in seguito. Non puoi semplicemente provare a elaborare tutti i file che arrivano perché ci sono tutti i tipi di casi in cui verranno generati più eventi per lo stesso file, quindi impostare un ciclo di tentativi su ogni singolo evento ricevuto può trasformarsi in un disastro, in fretta. È necessario metterli in coda e controllare la coda a intervalli regolari.

Ecco un modello di classe di base che dovrebbe aiutare con questo problema:

public class FileMonitor : IDisposable 
{ 
    private const int PollInterval = 5000; 

    private FileSystemWatcher watcher; 
    private HashSet<string> filesToProcess = new HashSet<string>(); 
    private Timer fileTimer; // System.Threading.Timer 

    public FileMonitor(string path) 
    { 
     if (path == null) 
      throw new ArgumentNullException("path"); 

     watcher = new FileSystemWatcher(); 
     watcher.Path = path; 
     watcher.NotifyFilter = NotifyFilters.FileName; 
     watcher.Created += new FileSystemEventHandler(FileCreated); 
     watcher.EnableRaisingEvents = true; 

     fileTimer = new Timer(new TimerCallback(ProcessFilesTimer), 
      null, PollInterval, Timeout.Infinite); 
    } 

    public void Dispose() 
    { 
     fileTimer.Dispose(); 
     watcher.Dispose(); 
    } 

    private void FileCreated(object source, FileSystemEventArgs e) 
    { 
     lock (filesToProcess) 
     { 
      filesToProcess.Add(e.FullPath); 
     } 
    } 

    private void ProcessFile(FileStream fs) 
    { 
     // Your code here... 
    } 

    private void ProcessFilesTimer(object state) 
    { 
     string[] currentFiles; 
     lock (filesToProcess) 
     { 
      currentFiles = filesToProcess.ToArray(); 
     } 
     foreach (string fileName in currentFiles) 
     { 
      TryProcessFile(fileName); 
     } 
     fileTimer.Change(PollInterval, Timeout.Infinite); 
    } 

    private void TryProcessFile(string fileName) 
    { 
     FileStream fs = null; 
     try 
     { 
      FileInfo fi = new FileInfo(fileName); 
      fs = fi.OpenRead(); 
     } 
     catch (IOException) 
     { 
      // Possibly log this error 
      return; 
     } 

     using (fs) 
     { 
      ProcessFile(fs); 
     } 

     lock (filesToProcess) 
     { 
      filesToProcess.Remove(fileName); 
     } 
    } 
} 

(Nota - sto Ricordando questo a memoria qui quindi potrebbe non essere perfetto - fatemi sapere se si tratta di buggy .)

+0

Bello, questo è quello che sono andato con mentre stavo aspettando. Ho usato un time-out e una nuova attesa, speravo che ci fosse qualcosa di più elegante, ma oh, va bene;) (Grazie mille per aver cercato di ottenere una grande risposta) – Matthew

Problemi correlati