2010-02-09 12 views
10

Tengo un sistema de archivos guardián que activará un evento cuando se modifique un archivo. Quiero leer de ese archivo una vez que se haya eliminado el bloqueo. Por el momento estoy intentando abrir el archivo una vez que se desencadena el evento, cuando se está copiando un archivo grande, el bloqueo de archivo permanece activo durante un tiempo después de que se han enviado los eventos, evitando que el archivo se abra para acceso de lectura.Activadores FileSystemWatcher para filestream open

¿Alguna sugerencia?

Respuesta

6

Esto en realidad es un poco raro, a menos que el espacio problemático haya cambiado significativamente desde la última vez que tuve que lidiar con él.

La manera más fácil es simplemente tratar de abrir el archivo, capturar el resultado IOException, y si el archivo está bloqueado, agréguelo a una cola para revisarlo más tarde. No puede tratar de procesar cada archivo que ingrese porque hay todo tipo de casos en los que se generarán múltiples eventos para el mismo archivo, por lo que configurar un ciclo de reintento en cada evento recibido puede convertirse en un desastre, rápido. En su lugar, debe ponerlos en cola y verificar la cola a intervalos regulares.

Aquí está una plantilla de clase básica que debe ayudar con este 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 - Estoy recordando esto desde la memoria aquí, así que puede que no sea perfecta - que me haga saber si se trata de cochecillo .)

+0

Bien, esto es lo que hice mientras esperaba. Usé un tiempo de espera y una espera de reintento, esperaba que hubiera algo más elegante, pero bueno;) (Gracias a un millón por ir al esfuerzo por una gran respuesta) – Matthew

Cuestiones relacionadas