2011-02-11 8 views
5

Esto es más una pregunta acerca de cuál es la mejor práctica en la implementación de esto.C# - Predecir eventos del sistema de archivos en la carpeta eliminar

Tengo un FileSystemWatcher que me debe informar acerca de los cambios del usuario en los archivos y carpetas. También se vigilan los subdires. En el mismo directorio, mi programa también a veces cambia. No deseo que FileSystemWatcher detecte eventos en estos cambios de programa.

Mi primera implementación fue una lista donde puedo agregar eventos esperados. Cuando recibo un evento del sistema de archivos, reviso la lista y la ignoro si está allí. Esto no suena muy robusto pero parece funcionar.

Ahora me detectaron el problema real:
D: se mira por el FileSystemWatcher.
Tengo dos carpetas como esa: D: \ carpeta1 \ carpeta2
Ahora quiero eliminar la carpeta1 (con la carpeta2 en ella) con mi aplicación. Así que puse D: \ folder1 en mi lista de eliminación. Luego llamo a algo así como Directory.Delete(@"D:\folder1", true). Ahora noto que la carpeta1 no se puede eliminar (por qué nunca) sobre una excepción. Elimino la entrada de eliminación de mi lista, pero la carpeta2 ya se eliminó y obtengo su FileSystemEvent. Entonces obtengo un evento FileSystem para D: \ folder1 \ folder2. Mi programa piensa que ahora el usuario ha eliminado esta carpeta y está haciendo las cosas mal.

que tenían algunas ideas ahora:

1.) eliminar de forma recursiva la carpeta mediante la supresión de todos los archivos y todas las carpetas por sí mismo. Con esto obtengo para cada subcarpeta y archivo una entrada de lista propia. Ya lo implementé, pero es muy, muy, muy lento.

2.) ¿Tal vez hay una mejor manera de tener filtros inteligentes en el FileSystemWatcher para hacer que mi lista quede obsoleta?

3.) Tal vez solo se pueda eliminar un árbol de directorios si es posible eliminar todo. Entonces, si falla, todavía tengo todo y si no, todo se elimina. Esta parece ser la solución más elegante para mí, pero no tengo idea de si esto es posible.

4.) ¿Es posible bloquear exclusivamente todos los archivos y carpetas de mi software? Si esto fue bien, debería ser posible borrar todo con un comando de eliminación o de alguna manera así?

También estoy abierto para otras soluciones adicionales.

Editar 1 para que sea más claro:

Sólo quiero "ver" las acciones del usuario en una carpeta. Si manipulo cosas de mi programa aquí, no quiero ver estos eventos.

Con mi implementación, obtengo eventos para subcarpetas si una carpeta está bloqueada y no se puede eliminar.

No es tan fácil de explicar en inglés porque no soy un hablante nativo de inglés;).

Edición 2:

5.) Tal vez es posible filtrar en FileSystemWatcher todos los eventos de un proceso definido?

+0

¿Dónde está la parte en su pregunta sobre cómo predecir las cosas? –

+0

la lista sobre la que estaba escribiendo es una predicción porque contiene los eventos esperados que deberían venir más tarde de FileSystemWatcher. Funciona así: 1.) recordar en la lista 2.) manipular archivos/carpeta 3.) ignorar eventos con la lista – fpdragon

+0

En serio, no estoy obteniendo esto. ¿Qué evento esperas? ¿Qué eventos estás recibiendo en su lugar? ¿Qué excepciones estás obteniendo? Por favor actualice sus preguntas con estos puntos. –

Respuesta

0

Ok aquí está mi solución del problema:

Sólo por comando de eliminación:

implementé 2 listas , uno para eliminar archivos y otro para eliminar carpetas.

las entradas de la lista de archivos no tienen tiempo de espera. Si elimino un archivo, creo una entrada de lista y si obtengo el evento de eliminación esperado, elimino la entrada como antes.

entrys de lista de carpetas no tienen tiempo de espera después de crear. Puedo ordenarles que se apaguen manualmente después de un segundo por un método especial. Si elimino una carpeta agrego una entrada de la lista deleteFolder. Cada evento de eliminación de esta carpeta o archivo o subcarpeta o archivo de subcarpetas se ignora debido a esta entrada de la carpeta de eliminación. Después de que la eliminación finalice, armo el tiempo de espera para la entrada deleteFolder. Si la eliminación arroja una excepción, hago lo mismo. Así que espero obtener todos los eventos después de un segundo. Por lo tanto, ignoro todos los eventos si el comando de eliminación funciona o no. Después de esto, la entrada de la lista deleteFolder se elimina.

Limitaciones: 1. todos los eventos de eliminación tienen que aparecer en un segundo después de que se haya eliminado. 2.no se permite eliminar una carpeta de esta manera:
carpeta de eliminación (terminado)
crear la carpeta de nuevo
esperar menos de 1 segundo
carpeta de eliminación de nuevo (tiempo de espera no ha terminado de la entrada de la lista de carpetas de borrado)

Espero que esto ayude a alguien, incluso si es muy complicado ^^

2

He hecho exactamente este tipo de cosas recientemente; el truco es hacer que su 'lista' reconozca que donde hay un nombre de carpeta en la lista, también descartar cualquier evento para cualquier cosa dentro de esa carpeta si está esperando un evento de eliminación, y solo eliminarlo de su lista de predicción si es la carpeta misma.

Debo advertirle, sin embargo, es probable que encuentre problemas con el búfer de FileSystemWatcher que se llena si demasiados eventos suceden en rápida sucesión; si esto ocurre, lanzará un evento Error y no le avisará de un montón de eventos. Si su lista de predicciones elimina elementos a medida que recibe el evento, se corre el riesgo de ignorar eventos futuros simplemente porque el evento que intentaba ignorar nunca se recibió debido a un desbordamiento del búfer. También puede ser muy grande, ya que los elementos nunca se eliminan de la lista.

Todavía tengo que encontrar una forma confiable de hacerlo, aunque puede establecer el tamaño del buffer FileSystemWatcher al máximo para mitigarlo hasta cierto punto.

EDIT: También muy importante: Los eventos que regresan lo hacen por un hilo diferente (a menos que su controlador está en un objeto que implementa ISynchronizeInvoke, tales como Control o Form, y se establece la SynchronizingObject a su Control/Form Esto significa que debe tener mucho cuidado con la forma en que mantiene su lista, teniendo en cuenta las posibles condiciones de carrera. Todavía estoy luchando con esta, mi código vacía la lista de predicciones al recibir un evento de error, pero para el momento en que maneja el evento, otros eventos de cambio ya que el error ya se ha disparado y manejado, y vacía cosas que no debería.

+0

muy muy interesante ... gracias. ¿sabes qué tan grande es este buffer FileSystemWatcher? También traté de implementar un tiempo de vida esperado para entrys de lista para limpiar esto un poco, pero la pregunta es qué tan rápido llegan los eventos FileSystem (peor caso)? Sería bueno si pudieras mantenerme actualizado y contarme tus experiencias. 1+ – fpdragon

+0

si tuviera esta implementación de por vida y sería robusta, podría usar expresiones regulares para eliminar carpetas y dejar que la entrada de la lista se agote. – fpdragon

+1

'FileSystemWatcher' tiene una propiedad' InternalBufferSize'. El valor predeterminado es 8k, pero puede ir hasta 64k. http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.internalbuffersize.aspx – Flynn1179

1

En cuanto al desbordamiento del búfer. La mejor manera de resolverlo es hacer el trabajo en respuesta a un evento en otro hilo. Lo hago como esto

// Queue of changed paths. 
private readonly Queue<string> mEventQueue = new Queue<string>(); 

// add this as handler for filesystemwatcher events 
public void FileSystemEvent(object source, FileSystemEventArgs e) { 
    lock (mEventQueue) { 
     if (!mEventQueue.Contains(e.FullPath)) { 
      mEventQueue.Enqueue(e.FullPath); 
      Monitor.Pulse(mEventQueue); 
     } 
    } 
} 

// start this on another thread 
public void WatchLoop() { 
    string path; 
    while (true) { 
     lock (mEventQueue) { 
      while (mEventQueue.Count == 0) 
       Monitor.Wait(mEventQueue); 
      path = mEventQueue.Dequeue(); 
      if (path == null) 
       break; 
     } 
     // do whatever you want to do 
    } 
} 

De esa manera Nunca se pierda un evento

+0

gracias ... Ya estoy teniendo algo similar. Estaba pensando en una situación en la que la PC está muy sobrecargada. No estoy seguro de si es posible, pero FileSystemWatcher predeterminado puede contener aproximadamente 500 entrys. Esto es mucho menos incluso si tiene un hilo de trabajo y simplemente pulsa los eventos desde el hilo de FileSystemWatcher. Así que no creo que sea un error establecer el búfer al máximo. – fpdragon

Cuestiones relacionadas