¿Cómo abro un archivo ya abierto con .NET StreamReader?

Tengo algunos archivos .csv que estoy usando como parte de un banco de pruebas. Puedo abrirlos y leerlos sin problemas a menos que ya tenga el archivo abierto en Excel, en cuyo caso obtengo una IOException :

System.IO.IOException: el proceso no puede acceder al archivo ‘TestData.csv’ porque lo está utilizando otro proceso.

Este es un fragmento del banco de pruebas:

 using (CsvReader csv = new CsvReader(new StreamReader(new FileStream(fullFilePath, FileMode.Open, FileAccess.Read)), false)) { // Process the file } 

¿Es esto una limitación de StreamReader? Puedo abrir el archivo en otras aplicaciones (Notepad ++ por ejemplo) por lo que no puede ser un problema de O / S. Tal vez necesito usar alguna otra clase? Si alguien sabe cómo puedo evitar esto (¡aparte de cerrar Excel!) Estaría muy agradecido.

Como dice Jared, no puedes hacer esto a menos que la otra entidad que tiene el archivo abierto permita lecturas compartidas. Excel permite lecturas compartidas, incluso para archivos que tiene abiertos para escribir. Por lo tanto, debe abrir filestream con el parámetro FileShare.ReadWrite .

El parámetro de FileShare a menudo se entiende mal. Indica qué otros abridores del archivo pueden hacer. Se aplica a abridores pasados ​​y futuros. Piense en FileShare no como una prohibición retroactiva de los abridores anteriores (por ejemplo, Excel), sino como una restricción que no se debe violar con el Abierto actual o cualquier Abierto futuro.

En el caso del bash actual de abrir un archivo, FileShare.Read dice “abrir este archivo para mí con éxito solo si alguno de los abridores anteriores lo ha abierto solo para lectura”. Si especifica FileShare.Read en un archivo que está abierto para escritura por Excel, su apertura fallará, ya que violaría la restricción, porque Excel la tiene abierta para escribir .

Debido a que Excel tiene el archivo abierto para escribir, debe abrir el archivo con FileShare.ReadWrite si desea que su apertura tenga éxito. Otra forma de pensar en el param de FileShare: especifica “el acceso al archivo del otro tipo”.

Ahora suponga un escenario diferente, en el que está abriendo un archivo que no está abierto actualmente por ninguna otra aplicación. FileShare.Read dice “los abridores futuros pueden abrir el archivo solo con acceso de lectura”.

Lógicamente, esta semántica tiene sentido: FileShare.Read significa que no desea leer el archivo si el otro tipo ya lo está escribiendo, y no desea que el otro escriba el archivo si ya lo está leyendo. FileShare.ReadWrite significa que está dispuesto a leer el archivo incluso si el otro lo está escribiendo, y no tiene ningún problema en dejar que otro abridor escriba el archivo mientras lo está leyendo.

En ningún caso esto permite múltiples escritores. FileShare es similar a una base de datos IsolationLevel. La configuración que desee aquí depende de las garantías de “coherencia” que necesita.

Ejemplo:

 using (Stream s = new FileStream(fullFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { ... } 

o,

 using (Stream s = System.IO.File.Open(fullFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { } 

Apéndice:

La documentación en System.IO.FileShare es un poco delgada. Si desea obtener los datos correctos, vaya a la documentación de la función Win32 CreateFile , que explica mejor el concepto de FileShare.

EDITAR

Todavía no estoy 100% seguro de por qué esta es la respuesta, pero puede solucionar este problema pasando FileShare.ReadWrite al constructor de FileStream.

 using (CsvReader csv = new CsvReader(new StreamReader(new FileStream(fullFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)), false) { ... } 

Mi curiosidad me atrapa en este momento y trato de entender por qué esta es la respuesta particular. Si lo resuelvo más tarde, lo actualizaré con la información.

La mejor documentación parece estar en la función CreateFile . Esta es la función que .Net llamará debajo del capó para abrir un archivo (crear un archivo es un nombre incorrecto). Tiene una mejor documentación sobre cómo funciona el aspecto de compartir de abrir un archivo. Otra opción es simplemente leer la respuesta de Cheeso

Si otro proceso tiene un archivo abierto, a menudo puede usar File.Copy y luego abrir la copia. No es una solución elegante, sino pragmática.

Otra pega es que si abre un FileStream con FileShare.ReadWrite , las siguientes aperturas de ese archivo también FileShare.ReadWrite especificar FileShare.ReadWrite , o obtendrá el error ‘Otro proceso está usando este archivo’.

Usando el Sistema.Diagnostics;

Simplemente puede llamar a Process.Start (“nombre de archivo y ruta”)

No estoy seguro de si eso ayuda, pero eso es lo que acabo de utilizar para implementar un botón de Vista previa en PDF en nuestra intranet.