Tengo una aplicación en la que busco un archivo de texto y, si se realizan cambios en el archivo, estoy usando el OnChanged
controlador de eventos para manejar el evento. Estoy usando el NotifyFilters.LastWriteTime
pero todavía el evento se dispara dos veces. Aquí está el código.
public void Initialize()
{
FileSystemWatcher _fileWatcher = new FileSystemWatcher();
_fileWatcher.Path = "C:\\Folder";
_fileWatcher.NotifyFilter = NotifyFilters.LastWrite;
_fileWatcher.Filter = "Version.txt";
_fileWatcher.Changed += new FileSystemEventHandler(OnChanged);
_fileWatcher.EnableRaisingEvents = true;
}
private void OnChanged(object source, FileSystemEventArgs e)
{
.......
}
En mi caso, OnChanged
se llama dos veces, cuando cambio el archivo de texto version.txt
y lo guardo.
c#
filesystemwatcher
usuario214707
fuente
fuente
Respuestas:
Me temo que este es un error / característica bien conocido de la
FileSystemWatcher
clase. Esto es de la documentación de la clase:Ahora, este fragmento de texto trata sobre el
Created
evento, pero lo mismo se aplica también a otros eventos de archivo. En algunas aplicaciones, es posible que pueda evitar esto utilizando laNotifyFilter
propiedad, pero mi experiencia dice que a veces también tiene que hacer un filtrado duplicado manual (piratería).Hace un tiempo reservé una página marcada con algunos consejos de FileSystemWatcher . Quizás quieras revisarlo.
fuente
He "solucionado" ese problema usando la siguiente estrategia en mi delegado:
fuente
Cualquier
OnChanged
evento duplicado delFileSystemWatcher
puede ser detectado y descartado marcando laFile.GetLastWriteTime
marca de tiempo en el archivo en cuestión. Al igual que:fuente
"Rename"
el nombre del evento que le interesa):Observable.FromEventPattern<FileSystemEventArgs>(fileSystemWatcher, "Renamed") .Select(e => e.EventArgs) .Distinct(e => e.FullPath) .Subscribe(onNext);
DateTime
solo tiene una resolución de milisegundos, este método funciona incluso si lo reemplazaFile.GetLastWriteTime
conDateTime.Now
. Dependiendo de su situación, también puede usar ela.FullName
en una variable global para detectar eventos duplicados.Aquí está mi solución que me ayudó a evitar que el evento se genere dos veces:
Aquí he establecido la
NotifyFilter
propiedad con solo Nombre de archivo y tamaño.watcher
es mi objeto de FileSystemWatcher. Espero que esto ayude.fuente
Mi escenario es que tengo una máquina virtual con un servidor Linux. Estoy desarrollando archivos en el host de Windows. Cuando cambio algo en una carpeta en el host, quiero que se carguen todos los cambios, sincronizados en el servidor virtual a través de Ftp. Así es como elimino el evento de cambio duplicado cuando escribo en un archivo (que marca la carpeta que contiene el archivo que se modificará también):
Principalmente creo una tabla hash para almacenar información de tiempo de escritura de archivos. Luego, si la tabla hash tiene la ruta de archivo modificada y su valor de tiempo es el mismo que el cambio del archivo notificado actualmente, entonces sé que es el duplicado del evento e ignórelo.
fuente
ToString("o")
pero prepárese para más fallas.Prueba con este código:
fuente
if (let==false) { ... } else { let = false; }
? Increíble cómo esto obtuvo votos positivos, esto debe ser solo una cuestión de insignias StackOverflow.Aquí está mi enfoque:
Esta es la solución que usé para resolver este problema en un proyecto donde estaba enviando el archivo como archivo adjunto en un correo. Evitará fácilmente el evento que se disparó dos veces, incluso con un intervalo de temporizador más pequeño, pero en mi caso 1000 estuvo bien, ya que estaba más feliz con la falta de pocos cambios que con inundar el buzón con> 1 mensaje por segundo. Al menos funciona bien en caso de que se cambien varios archivos al mismo tiempo.
Otra solución que he pensado sería reemplazar la lista con un archivo de mapeo de diccionario a su MD5 respectivo, para que no tenga que elegir un intervalo arbitrario ya que no tendría que eliminar la entrada pero actualizar su valor, y cancela tus cosas si no ha cambiado. Tiene la desventaja de tener un Diccionario creciendo en la memoria a medida que se monitorean los archivos y consumiendo más y más memoria, pero he leído en alguna parte que la cantidad de archivos monitoreados depende del búfer interno del FSW, por lo que tal vez no sea tan crítico. No sé cómo el tiempo de computación MD5 afectaría el rendimiento de su código tampoco, cuidado = \
fuente
lock (_changedFiles) { if (_changedFiles.Contains(e.FullPath)) { return; } _changedFiles.Add(e.FullPath); // add this! } // do your stuff
_changedFiles
accede al desde múltiples hilos. Una forma de solucionarlo es usar un enConcurrentDictionary
lugar deList
. Otra forma es asignar la corrienteForm
a laTimer.SynchronizingObject
propiedad, así como a laFileSystemWatcher.SynchronizingObject
propiedad.He creado un repositorio de Git con una clase que se extiende
FileSystemWatcher
para desencadenar los eventos solo cuando se realiza la copia. Descarta todos los eventos modificados excepto el último y lo genera solo cuando el archivo está disponible para leer.Descargue FileSystemSafeWatcher y agréguelo a su proyecto.
Luego, úselo normalmente
FileSystemWatcher
y controle cuándo se desencadenan los eventos.fuente
Sé que este es un problema antiguo, pero tenía el mismo problema y ninguna de las soluciones anteriores realmente resolvió el problema que estaba enfrentando. He creado un diccionario que asigna el nombre del archivo con LastWriteTime. Entonces, si el archivo no está en el diccionario, continuará con el proceso; de lo contrario, verifique cuándo fue la última vez que se modificó y si es diferente de lo que está en el diccionario, ejecute el código.
fuente
your code here
sección, debe agregar o actualizar dateTimeDictionary.dateTimeDictionary[e.FullPath] = System.IO.File.GetLastWriteTime(e.FullPath);
Un posible 'pirateo' sería limitar los eventos usando Extensiones reactivas, por ejemplo:
En este caso, estoy acelerando a 50 ms, en mi sistema eso fue suficiente, pero los valores más altos deberían ser más seguros. (Y como dije, sigue siendo un 'hack').
fuente
.Distinct(e => e.FullPath)
que me parece mucho más intuitivo. Y tiene el comportamiento restaurado que se esperaría de la API.Tengo una solución muy rápida y simple aquí, funciona para mí, y no importa que el evento se desencadene una o dos veces o más veces ocasionalmente, échale un vistazo:
fuente
Aquí hay una nueva solución que puedes probar. Funciona bien para mi En el controlador de eventos para el evento modificado, elimine mediante programación el controlador del diseñador, envíe un mensaje si lo desea y luego vuelva a agregar el controlador mediante programación. ejemplo:
fuente
this.fileSystemWatcher1.Changed -= this.fileSystemWatcher1_Changed;
Debería hacer lo correcto.La razón principal fue que la última hora de acceso del primer evento fue la hora actual (escritura de archivo o hora cambiada). entonces el segundo evento fue el último tiempo de acceso original del archivo. Lo resuelvo bajo código.
fuente
Pasé una cantidad significativa de tiempo usando FileSystemWatcher, y algunos de los enfoques aquí no funcionarán. Realmente me gustó el enfoque de eventos de desactivación, pero desafortunadamente, no funciona si se cae> 1 archivo, el segundo archivo se perderá la mayoría, si no todas las veces. Entonces uso el siguiente enfoque:
fuente
Este código me funcionó.
fuente
principalmente para mi futuro :)
Escribí un contenedor usando Rx:
Uso:
fuente
He cambiado la forma en que superviso los archivos en los directorios. En lugar de usar FileSystemWatcher, sondeo ubicaciones en otro hilo y luego miro el LastWriteTime del archivo.
Utilizando esta información y manteniendo un índice de una ruta de archivo y su último tiempo de escritura, puedo determinar los archivos que han cambiado o que se han creado en una ubicación particular. Esto me elimina de las rarezas del FileSystemWatcher. El principal inconveniente es que necesita una estructura de datos para almacenar LastWriteTime y la referencia al archivo, pero es confiable y fácil de implementar.
fuente
Podría intentar abrirlo para escribir, y si tiene éxito, podría suponer que la otra aplicación se ha completado con el archivo.
Simplemente abrirlo para escribir parece no generar el evento modificado. Entonces debería ser seguro.
fuente
fuente
Perdón por la excavación de tumbas, pero he estado luchando contra este problema por un tiempo y finalmente encontré una manera de manejar estos eventos disparados múltiples. Me gustaría agradecer a todos en este hilo, ya que lo he usado en muchas referencias al luchar contra este problema.
Aquí está mi código completo. Utiliza un diccionario para rastrear la fecha y la hora de la última escritura del archivo. Compara ese valor y, si es el mismo, suprime los eventos. Luego establece el valor después de comenzar el nuevo hilo.
fuente
Evento si no se pregunta, es una pena que no haya muestras de solución listas para F #. Arreglar esto aquí es mi receta, solo porque puedo y F # es un maravilloso lenguaje .NET.
Los eventos duplicados se filtran usando el
FSharp.Control.Reactive
paquete, que es solo un contenedor F # para extensiones reactivas. Todo lo que puede orientarse a un marco completo onetstandard2.0
:fuente
En mi caso, necesito obtener la última línea de un archivo de texto que se inserta por otra aplicación, tan pronto como se realiza la inserción. Aquí está mi solución. Cuando se genera el primer evento, desactivo al observador para que no genere otros, luego llamo al temporizador TimeElapsedEvent porque cuando se llama a mi función de control OnChanged necesito el tamaño del archivo de texto, pero el tamaño en ese momento no es el tamaño real, es el tamaño del archivo inmediatamente antes de la inserción. Así que espero un momento para proceder con el tamaño de archivo correcto.
fuente
Prueba esto, está funcionando bien
fuente
Quería reaccionar solo en el último evento, por si acaso, también en un cambio de archivo de Linux, parecía que el archivo estaba vacío en la primera llamada y luego se rellenaba en la siguiente y no me importaba perder algo de tiempo en caso de que el sistema operativo decidió hacer algún cambio de archivo / atributo.
Estoy usando .NET async aquí para ayudarme a hacer el subproceso.
fuente
Creo que la mejor solución para resolver el problema es usar extensiones reactivas. Cuando transforma el evento en observable, simplemente puede agregar Throttling (..) (originalmente llamado Debounce (..))
Código de muestra aquí
fuente
Pude hacer esto agregando una función que busca duplicados en una matriz de búfer.
Luego realice la acción después de que la matriz no haya sido modificada por tiempo X usando un temporizador: - Restablezca el temporizador cada vez que se escriba algo en el búfer - Realice una acción al marcar
Esto también atrapa otro tipo de duplicación. Si modifica un archivo dentro de una carpeta, la carpeta también genera un evento Change.
fuente
Esta solución me funcionó en la aplicación de producción:
Ambiente:
VB.Net Framework 4.5.2
Establecer manualmente las propiedades del objeto: NotifyFilter = Tamaño
Luego usa este código:
fuente
¡Prueba esto!
fuente
Tuve que combinar varias ideas de las publicaciones anteriores y agregar la comprobación de bloqueo de archivos para que funcione:
fuente
Me acerqué al problema de doble creación como este, que ignora el primer evento:
fuente