¿Por qué recibo una excepción no controlada: System.IO.IOException al intentar leer un archivo en el que se está escribiendo?

Tengo dos aplicaciones de C #, una es leer un archivo (archivo A) línea por línea y escribir su contenido en un archivo diferente (archivo B).

La segunda aplicación utiliza FileSystemWatcher for File B para ver cuándo se actualiza y notifica la diferencia entre los números de línea entre cuándo se inició el progtwig y cuándo se cambió el archivo.

Eso es todo lo que estoy tratando de hacer por ahora; en última instancia, quiero leer las líneas entre la última vez que se leyó el archivo y la lectura actual, pero hasta que pueda obtener la diferencia de línea que está en espera.

El código que tengo para la aplicación 1 es;

static void Main(string[] args) { String line; StreamReader sr = new StreamReader("f:\\watch\\input.txt"); FileStream fs = new FileStream("f:\\watch\\Chat.log", FileMode.Create, FileAccess.Write, FileShare.ReadWrite); StreamWriter sw = new StreamWriter(fs); while ((line = sr.ReadLine()) != null) { sw.WriteLine(line); Thread.Sleep(200); Console.WriteLine(line); sw.Flush(); } sw.Close(); sr.Close(); } 

El código que tengo para la aplicación 2 es;

  public static int lines = 0; public static void Main() { Run(); } public static void Run() { string[] args = System.Environment.GetCommandLineArgs(); if (args.Length != 2) { Console.WriteLine("Usage: Watcher.exe (directory)"); return; } FileSystemWatcher watcher = new FileSystemWatcher(); watcher.Path = args[1]; watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; watcher.Filter = "Chat.log"; watcher.Changed += new FileSystemEventHandler(OnChanged); watcher.EnableRaisingEvents = true; lines = File.ReadAllLines(args[1] + "\\Chat.log").Length; Console.WriteLine("File lines: " + lines); while(Console.Read()!='q'); } private static void OnChanged(object source, FileSystemEventArgs e) { Linework(e.FullPath); Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType); } public static string Linework(string path) { string newstring = " "; using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { int newlines = File.ReadAllLines(path).Length; Console.WriteLine("Lines now: " + newlines); } return newstring; } 

Ahora, cuando bash ejecutar estas dos aplicaciones juntas, obtengo una excepción que dice “Excepción no controlada: System.IO.IOException: el proceso no puede acceder al archivo porque otro proceso lo está utilizando”.

Tengo ambas configuraciones de secuencias de archivos para el acceso de ReadWrite y tengo una de las configuraciones de secuencias de archivos para FileAccess.Write y la otra para FileAccess.Read.

¿Alguna pista de por qué obtendría esta excepción?

Gracias Hew.

líneas = File.ReadAllLines (args [1] + “\ Chat.log”). Longitud;

Ahí está tu problema. Ese método abre el archivo, lee todas las líneas y lo cierra de nuevo. Utiliza la configuración de archivos compartidos “normales” al abrir el archivo, FileShare.Read. Eso niega el acceso de escritura a cualquier otro proceso que también tenga el archivo abierto.

Eso no puede funcionar aquí, ya tienes el archivo abierto con acceso de escritura. El segundo proceso no puede negarlo. La IOException es el resultado.

No puede usar File.ReadAllLines () tal como está aquí, debe abrir un FileStream con FileShare.ReadWrite, pasarlo a un StreamReader y leer todas las líneas.

Cuidado con el potencial de carrera muy problemático que tienes aquí, no hay garantía de que la última línea que leerás sea una línea completa. Obtener solo un \ ry no el \ n al final de la línea es un problema particularmente difícil. Esto se producirá de forma aleatoria e infrecuente, los errores más difíciles de solucionar. Tal vez tu llamada de Flush () lo arregla, nunca he sido lo suficientemente valiente como para poner esto a prueba.

Permitir que el segundo progtwig ReadWrite acceso en el archivo funcionaría en este caso.

 //lines = File.ReadAllLines(args[1] + "\\Chat.log").Length; //Commenting the above lines as this would again open a new filestream on the chat.log //without the proper access mode required. using (FileStream fsReader = new FileStream(args[1] + "\\Chat.log", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) { using (StreamReader sr = new StreamReader(fsReader)) { while (sr.ReadLine() != null) lines++; } } 
 StreamReader sr = new StreamReader("f:\\watch\\input.txt"); 

input.txt podría no estar disponible para leer?

También use la instrucción using lugar de Close () en la primera aplicación (en caso de que se produzca una excepción).

De lo contrario está bien. Sin embargo, el recurso compartido de archivos puede requerir permisos adicionales (realmente no puede afectar eso).

Me he perdido una pieza de código:

 int newlines = File.ReadAllLines(path).Length; 

usa la stream con un StreamReader para eso.

MSDN ofrece dos formas de no obtener una retención exclusiva:

Un objeto FileStream no tendrá una retención exclusiva en su identificador cuando se accede a la propiedad SafeFileHandle para exponer el identificador o al objeto FileStream se le asigna la propiedad SafeFileHandle en su constructor.

La documentación implica que lo inverso es verdadero:

Abrir un FileStream sin configurar SafeFileHandle significa que FileStream mantiene una retención exclusiva en el identificador de archivo (que está en línea con la excepción de IO que se supone que debe ser lanzada).