2010-12-27 19 views
5

Tengo una aplicación que inicia otras aplicaciones y luego espera a que creen un archivo de datos específico (observa una aplicación a la vez). Cada vez que se lanza una aplicación, observa un directorio específico para crear un archivo específico. Estoy usando FileSystemWatcher para hacer esto (configurarlo en el directorio, luego filtrar el nombre correcto del archivo). Esto funciona genial la primera vez (siempre), pero la segunda aplicación lanzada nunca dispara el evento. La única forma en que parece desencadenar el evento es si coloco un punto de interrupción en el controlador de eventos, o si tengo un comando Thread.Sleep en el controlador de eventos. Esto me parece muy extraño ... ¿hay alguna condición de carrera de la que no tengo conocimiento? Aquí está el código. Tenga en cuenta que tengo un Thread.Sleep (500). Con esta línea el código funciona todo el tiempo. Sin eso, fallará. Realmente no me siento cómodo confiando en un comando de Suspensión. No estoy seguro de qué condición hará que no funcione tan bien.FileSystemWatcher - evento que no se activa por segunda vez

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

Alguien sabe por qué tengo que tener ese sueño (o punto de ruptura) para obtener el código para trabajar por segunda vez?

+0

este código se ve bien para mí. – Simone

+5

nota: no es necesario que use 'e.ChangeType.ToString()' en el interruptor, solo active 'e.ChangeType' y establezca los casos' ChangeType.XXX'. Esto lo hace fuertemente tipado y menos propenso a errores. – Femaref

+0

El observador del sistema de archivos parece tener muchas advertencias. http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.oncreated.aspx Dicho esto, ¿está seguro de que los diversos observadores no miran el mismo directorio? – NotMe

Respuesta

1

De acuerdo con la documentación de la clase System.IO.FileSystemWatcher:

El sistema operativo Windows notifica a su componente de cambios en los archivos en una memoria intermedia creada por el FileSystemWatcher. Si hay muchos cambios en poco tiempo, el buffer puede desbordarse. Esto hace que el componente pierda de vista los cambios en el directorio, y solo proporcionará una notificación general. Aumentar el tamaño del búfer con la propiedad InternalBufferSize es costoso, ya que proviene de una memoria no paginada que no se puede intercambiar en el disco, por lo que debe mantener el búfer lo suficientemente pequeño como para no perder ningún evento de cambio de archivo. Para evitar un desbordamiento del búfer, use las propiedades NotifyFilter e IncludeSubdirectories para que pueda filtrar las notificaciones de cambios no deseados.

Es posible que el evento no se consuma lo suficientemente rápido y que el búfer interno no sea lo suficientemente grande como para manejar todas las notificaciones. De forma predeterminada, el monitor maneja las notificaciones FileName, DirectoryName, LastWrite, pero solo consume eventos de creación (tanto archivos como directorios). ¿Sus aplicaciones se ejecutan en rápida sucesión? Intentaría poner un retraso entre las invocaciones de sus aplicaciones (en lugar del controlador de eventos), usar filtros más específicos (solo la notificación FileName o solo mirar archivos de registro usando la propiedad Filter), aumentar el tamaño del búfer interno o cualquier combinación de los anteriores. Creo que eso debería arreglar tu problema.

+1

Las otras aplicaciones no se están ejecutando en una sucesión rápida. Puedo esperar unos segundos o unos minutos entre el lanzamiento de diferentes aplicaciones con los mismos resultados. – cwo

+0

@cwo: Entonces es posible que pueda salirse con la suya dejando de lado los retrasos si prueba las otras cosas que he mencionado. –

0

Estás visitando un solo evento "Creado". También debe escuchar todos los demás: OnChanged, OnDeleted - http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.aspx

EDITAR: La mayoría de los programas no "Crearán" el archivo cuando ya exista uno. Puede usar FileMon (ahora Process Monitor - http://technet.microsoft.com/en-us/sysinternals/bb896645) para ver qué operaciones realiza cada programa con su archivo.

+0

El evento creado es el único en el que estoy interesado. Los otros casos en la declaración de cambio solo estaban allí para probar el sistema de archivos vigilante al principio. Cuando se crea el archivo, necesito analizarlo. La forma en que funciona los archivos nunca se cambiarán, eliminarán ni cambiarán de nombre (o si lo son, no me importa). – cwo

+0

Pruebe usar Process Monitor para verificar sus suposiciones. Sospecho que no hay operaciones de "Crear" realizadas por otros programas ... O al menos sabrá con certeza que el problema está con su código, no con las notificaciones. –

+0

He verificado que el archivo se está creando en la ubicación correcta. He estado usando Process Explorer. Pero también puedo abrir el directorio en cuestión y ver que el archivo se está creando. – cwo

0

Me estoy enfrentando exactamente el mismo problema aquí (con Windows XP). Tu hack resuelve el problema. Me gustaría agregar algunas notas que podrían ser relevantes.

En mi caso, el nombre de archivo es siempre el mismo: C: \ blah.txt se crea, elimina, crea y así sucesivamente. Además, estoy usando un truco para ocultar mi solicitud:

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

Mi vigilante archivo funciona en modo de depuración o cuando agrego el sueño truco de los suyos. Ciertamente parece un error en el 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 variable watcher es elegible para la recolección de basura al final de este método. En lugar de ser una variable local, conviértalo en un miembro de nivel de clase como tal:

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; 
} 
Cuestiones relacionadas