tipos - En C#, si 2 procesos están leyendo y escribiendo en el mismo archivo, ¿cuál es la mejor manera de evitar excepciones de bloqueo de procesos?
tipos de excepciones en programacion (8)
¿Hay alguna razón en particular para abrir el archivo con FileShare.None? Eso evitará que otro proceso abra el archivo.
FileShare.Write o FileShare.ReadWrite deben permitir que el otro proceso (sujeto a permisos) se abra y escriba en el archivo mientras lo está leyendo, sin embargo, tendrá que observar el cambio del archivo debajo de usted mientras lo lee, simplemente almacenando en el búfer el contenido al abrir puede ayudar aquí.
Todas estas respuestas, sin embargo, son igualmente válidas: la mejor solución depende exactamente de lo que intentes hacer con el archivo: si es importante leerlo mientras se garantiza que no cambia, bloquearlo y manejar la siguiente excepción en tu código de escritura; si es importante leer y escribir al mismo tiempo, entonces cambie la constante de FileShare.
Con el siguiente código de lectura de archivo:
using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.None))
{
using (TextReader tr = new StreamReader(fileStream))
{
string fileContents = tr.ReadToEnd();
}
}
Y el siguiente código de escritura de archivo:
using (TextWriter tw = new StreamWriter(fileName))
{
tw.Write(fileContents);
tw.Close();
}
Se ven los siguientes detalles de excepción:
El proceso no puede acceder al archivo ''c: / temp / myfile.txt'' porque lo está utilizando otro proceso.
¿Cuál es la mejor manera de evitar esto? ¿El lector debe volver a intentar al recibir la excepción o hay alguna forma mejor?
Tenga en cuenta que el proceso de lectura utiliza un FileSystemWatcher para saber cuándo ha cambiado el archivo.
También tenga en cuenta que, en este caso, no estoy buscando formas alternativas de compartir cadenas entre los 2 procesos.
Escribir en un archivo temporal, cuando termine de escribir renombre / mueva el archivo a la ubicación y / o nombre que el lector está buscando.
Lo mejor que puede hacer es colocar un protocolo de aplicación sobre un mecanismo de transferencia de archivos / propiedad. El mecanismo de "bloqueo de archivo" es un viejo truco de UNIX que ha existido por siglos. Lo mejor que puede hacer es simplemente "entregarle" el archivo al lector. Hay muchas formas de hacer esto. Puede crear el archivo con un nombre de archivo aleatorio y luego "dar" ese nombre al lector. Eso le permitiría al escritor escribir de manera asíncrona otro archivo. Piensa en cómo funciona la "página web". Una página web tiene un "enlace" a más información, imágenes, scripts, contenido externo, etc. El servidor le entrega esa página, porque es una vista coherente del "recurso" que desea. Luego, su navegador se activa y obtiene el contenido apropiado, según la descripción de la página (el archivo HTML u otro contenido devuelto), y luego transfiere lo que necesita.
Este es el tipo más flexible de mecanismo de "compartir" para usar. Escribe el archivo, comparte el nombre, pasa al siguiente archivo. La parte "compartir el nombre" es la mano atómica que asegura que ambas partes (el lector y el escritor) estén de acuerdo en que el contenido es "completo".
Obtenga su proceso para verificar el estado del archivo si se está escribiendo. Puede hacerlo mediante la presencia de un archivo de bloqueo (es decir, la presencia de este otro archivo, que puede estar vacío, evita que se escriba en el archivo principal).
Sin embargo, incluso esto no es a prueba de fallas, ya que los dos procesos pueden crear el archivo de bloqueo al mismo tiempo, pero puede verificar esto antes de confirmar la escritura.
Si su proceso encuentra un archivo de bloqueo, póngalo simplemente en modo reposo / espera y vuelva a intentarlo en un intervalo predefinido en el futuro.
Puede abrir un archivo para escribir y solo bloquear el acceso de escritura, permitiendo así que otros sigan leyendo el archivo.
Por ejemplo,
using (FileStream stream = new FileStream(@"C:/Myfile.txt", FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
{
// Do your writing here.
}
Otro acceso a archivos solo abre el archivo para leer y no escribir, y permite el intercambio de lectura y escritura.
using (FileStream stream = new FileStream(@"C:/Myfile.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
// Does reading here.
}
Si quiere asegurarse de que los lectores siempre lean un archivo actualizado, necesitará usar un archivo de bloqueo que indique que alguien está escribiendo en el archivo (aunque puede obtener una condición de carrera si no se implementa cuidadosamente) o hacer asegúrese de bloquear el uso compartido de escritura al abrir para leer y manejar la excepción, de modo que puede volver a intentarlo hasta que obtenga acceso exclusivo.
Puede usar un objeto Mutex
para esto.
Si crea un Mutex con nombre, puede definir el mutex en la aplicación de escritura y hacer que la aplicación de lectura espere hasta que se libere el mutex.
Entonces, en el proceso de notificación que está trabajando actualmente con FileSystemWatcher, simplemente verifique si necesita esperar el mutex; si lo hace, esperará y luego procesará.
Aquí hay un ejemplo de VB de un Mutex como este que encontré, debería ser lo suficientemente fácil de convertir a C #.
Tanto el lector como el escritor necesitan mecanismos de reintento. También FileShare debe establecerse en FileShare.read para los lectores y FileShare.none para el escritor. Esto debería asegurar que los lectores no lean el archivo mientras la escritura está en progreso.
El lector (sin reintentar) se convierte
using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (TextReader tr = new StreamReader(fileStream))
{
string fileContents = tr.ReadToEnd();
}
}
El escritor (sin reintentar) se convierte en:
FileStream fileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
using (TextWriter tw = new StreamWriter(fileStream))
{
tw.Write(fileContents);
tw.Close();
}