¿Cuál es la forma más sencilla de bloquear un hilo hasta que se desbloquee un archivo y se pueda acceder a él para leerlo y cambiarle el nombre? Por ejemplo, ¿hay WaitOnFile () en algún lugar de .NET Framework?
Tengo un servicio que usa FileSystemWatcher para buscar archivos que se van a transmitir a un sitio FTP, pero el evento creado por el archivo se activa antes de que el otro proceso haya terminado de escribir el archivo.
La solución ideal tendría un período de tiempo de espera para que el hilo no cuelgue para siempre antes de darse por vencido.
Editar: Después de probar algunas de las soluciones a continuación, terminé cambiando el sistema para que todos los archivos se escribieran y Path.GetTempFileName()
luego realicé una File.Move()
en la ubicación final. Tan pronto como FileSystemWatcher
se disparó el evento, el archivo ya estaba completo.
Respuestas:
Esta fue la respuesta que di a una pregunta relacionada :
fuente
A partir de la respuesta de Eric, incluí algunas mejoras para hacer el código mucho más compacto y reutilizable. Espero que sea de utilidad.
fuente
using
en un nulo, solo verifique si hay nulo dentro delusing
bloque.fs
ser nula en elcatch
bloque? Si elFileStream
constructor arroja, no se le asignará un valor a la variable, y no hay nada más dentrotry
que pueda arrojar unIOException
. A mí me parece que debería estar bien hacerloreturn new FileStream(...)
.Aquí hay un código genérico para hacer esto, independiente de la operación del archivo en sí. Este es un ejemplo de cómo usarlo:
o
También puede definir el número de reintentos y el tiempo de espera entre reintentos.
NOTA: Desafortunadamente, el error subyacente de Win32 (ERROR_SHARING_VIOLATION) no está expuesto con .NET, por lo que agregué una pequeña función de pirateo (
IsSharingViolation
) basada en mecanismos de reflexión para verificar esto.fuente
SharingViolationException
. De hecho, todavía pueden, de manera compatible con versiones anteriores, siempre que descienda deIOException
. Y realmente deberían hacerlo.Starting with the .NET Framework 4.5, the HResult property's setter is protected, whereas its getter is public. In previous versions of the .NET Framework, both getter and setter are protected.
Organice una clase de ayuda para este tipo de cosas. Funcionará si tiene control sobre todo lo que accedería al archivo. Si espera una contención de muchas otras cosas, entonces esto es bastante inútil.
Funciona usando un mutex con nombre. Aquellos que deseen acceder al archivo intentan adquirir el control del mutex nombrado, que comparte el nombre del archivo (con las '\' convertidas en '/' s). Puede usar Open (), que se detendrá hasta que se pueda acceder al mutex, o puede usar TryOpen (TimeSpan), que intenta adquirir el mutex durante la duración determinada y devuelve falso si no puede adquirirlo dentro del intervalo de tiempo. Lo más probable es que esto se use dentro de un bloque de uso, para garantizar que las cerraduras se liberen correctamente y que la corriente (si está abierta) se eliminará correctamente cuando se elimine este objeto.
Hice una prueba rápida con ~ 20 cosas para hacer varias lecturas / escrituras del archivo y no vi ninguna corrupción. Obviamente, no es muy avanzado, pero debería funcionar para la mayoría de los casos simples.
fuente
Para esta aplicación en particular, observar directamente el archivo conducirá inevitablemente a un error difícil de rastrear, especialmente cuando aumenta el tamaño del archivo. Aquí hay dos estrategias diferentes que funcionarán.
¡Buena suerte!
fuente
Una de las técnicas que utilicé hace algún tiempo fue escribir mi propia función. Básicamente, detecta la excepción y vuelve a intentarlo con un temporizador que puedes disparar durante una duración determinada. Si hay una mejor manera, por favor compártala.
fuente
Desde MSDN :
Su FileSystemWatcher podría modificarse para que no haga su lectura / cambio de nombre durante el evento "OnCreated", sino más bien:
fuente
En la mayoría de los casos, un enfoque simple como el sugerido por @harpo funcionará. Puede desarrollar código más sofisticado usando este enfoque:
fuente
Anuncio para transferir el archivo de activación del proceso SameNameASTrasferedFile.trg que se crea después de que se completa la transmisión del archivo.
Luego configure FileSystemWatcher que activará el evento solo en el archivo * .trg.
fuente
No sé qué está usando para determinar el estado de bloqueo del archivo, pero algo como esto debería hacerlo.
fuente
Una posible solución sería combinar un observador del sistema de archivos con un sondeo,
reciba una notificación por cada cambio en un archivo y, al recibir una notificación, verifique si está bloqueado como se indica en la respuesta actualmente aceptada: https://stackoverflow.com/a/50800/6754146 El código para abrir el flujo de archivos se copia de la respuesta y ligeramente modificado:
De esta manera, puede verificar un archivo si está bloqueado y recibir una notificación cuando se cierre sobre la devolución de llamada especificada, de esta manera evita el sondeo demasiado agresivo y solo hace el trabajo cuando puede estar realmente cerrado
fuente
Lo hago de la misma manera que Gulzar, solo sigue intentándolo con un bucle.
De hecho, ni siquiera me preocupo por el observador del sistema de archivos. Sondear una unidad de red en busca de archivos nuevos una vez por minuto es barato.
fuente
Simplemente use el evento Changed con NotifyFilter NotifyFilters.LastWrite :
fuente
Me encontré con un problema similar al agregar un archivo adjunto de Outlook. "Usar" salvó el día.
fuente
¿Qué tal esto como una opción?
Por supuesto, si el archivo está preasignado en la creación, obtendría un falso positivo.
fuente