IOException: el proceso no puede acceder al archivo 'ruta del archivo' porque está siendo utilizado por otro proceso
Tengo un código y cuando se ejecuta, arroja un mensaje IOException
que dice que
El proceso no puede acceder al archivo 'nombre de archivo' porque está siendo utilizado por otro proceso
¿Qué significa esto y qué puedo hacer al respecto?
¿Cual es la causa?
El mensaje de error es bastante claro: estás intentando acceder a un archivo y no es accesible porque otro proceso (o incluso el mismo proceso) está haciendo algo con él (y no permite compartirlo).
Depuración
Puede ser bastante fácil de resolver (o bastante difícil de entender), dependiendo de su escenario específico. Veamos algunos.
Su proceso es el único que puede acceder a ese archivo.
Está seguro de que el otro proceso es el suyo. Si sabe que abre ese archivo en otra parte de su programa, primero que nada debe verificar que cierra correctamente el identificador del archivo después de cada uso. Aquí hay un ejemplo de código con este error:
var stream = new FileStream(path, FileAccess.Read);
var reader = new StreamReader(stream);
// Read data from this file, when I'm done I don't need it any more
File.Delete(path); // IOException: file is in use
Afortunadamente FileStream
se implementa IDisposable
, por lo que es fácil envolver todo el código dentro de una using
declaración:
using (var stream = File.Open("myfile.txt", FileMode.Open)) {
// Use stream
}
// Here stream is not accessible and it has been closed (also if
// an exception is thrown and stack unrolled
Este patrón también garantizará que el archivo no quede abierto en caso de excepciones (puede ser la razón por la que el archivo está en uso: algo salió mal y nadie lo cerró; consulte esta publicación para ver un ejemplo).
Si todo parece estar bien (está seguro de que siempre cierra todos los archivos que abre, incluso en caso de excepciones) y tiene varios subprocesos en funcionamiento, entonces tiene dos opciones: reelaborar su código para serializar el acceso a los archivos (no siempre es factible y no siempre deseado) o aplicar un patrón de reintento . Es un patrón bastante común para las operaciones de E/S: intentas hacer algo y, en caso de error, esperas y vuelves a intentarlo (¿te preguntaste por qué, por ejemplo, Windows Shell tarda algún tiempo en informarte que un archivo está en uso? y no se puede eliminar?). En C# es bastante fácil de implementar (consulte también mejores ejemplos sobre E/S de disco , redes y acceso a bases de datos ).
private const int NumberOfRetries = 3;
private const int DelayOnRetry = 1000;
for (int i=1; i <= NumberOfRetries; ++i) {
try {
// Do stuff with file
break; // When done we can break loop
}
catch (IOException e) when (i <= NumberOfRetries) {
// You may check error code to filter some exceptions, not every error
// can be recovered.
Thread.Sleep(DelayOnRetry);
}
}
Tenga en cuenta un error común que vemos con mucha frecuencia en StackOverflow:
var stream = File.Open(path, FileOpen.Read);
var content = File.ReadAllText(path);
En este caso ReadAllText()
fallará porque el archivo está en uso ( File.Open()
en la línea anterior). Abrir el archivo de antemano no sólo es innecesario sino también incorrecto. Lo mismo se aplica a todas File
las funciones que no devuelven un identificador al archivo con el que estás trabajando: File.ReadAllText()
, File.WriteAllText()
, File.ReadAllLines()
y File.WriteAllLines()
otras (como File.AppendAllXyz()
funciones) abrirán y cerrarán el archivo por sí mismas.
Su proceso no es el único que accede a ese archivo.
Si su proceso no es el único que accede a ese archivo, entonces la interacción puede ser más difícil. Un patrón de reintento ayudará (si nadie más debe abrir el archivo, pero sí lo está, entonces necesita una utilidad como Process Explorer para verificar quién está haciendo qué ).
Maneras de evitar
Cuando corresponda, utilice siempre declaraciones de uso para abrir archivos. Como se dijo en el párrafo anterior, lo ayudará activamente a evitar muchos errores comunes (consulte esta publicación para ver un ejemplo sobre cómo no usarlo ).
Si es posible, intente decidir quién posee el acceso a un archivo específico y centralice el acceso mediante algunos métodos conocidos. Si, por ejemplo, tiene un archivo de datos donde su programa lee y escribe, entonces debe encuadrar todo el código de E/S dentro de una sola clase. Hará que la depuración sea más fácil (porque siempre puedes poner un punto de interrupción allí y ver quién está haciendo qué) y también será un punto de sincronización (si es necesario) para acceso múltiple.
No olvide que las operaciones de E/S siempre pueden fallar; un ejemplo común es este:
if (File.Exists(path))
File.Delete(path);
Si alguien elimina el archivo después File.Exists()
pero antes File.Delete()
, lo arrojará IOException
a un lugar donde puede sentirse seguro erróneamente.
Siempre que sea posible, aplique un patrón de reintento y, si está utilizando FileSystemWatcher
, considere posponer la acción (porque recibirá una notificación, pero es posible que una aplicación aún esté funcionando exclusivamente con ese archivo).
Escenarios avanzados
No siempre es tan fácil, por lo que es posible que tengas que compartir el acceso con otra persona. Si, por ejemplo, estás leyendo desde el principio y escribiendo hasta el final, tienes al menos dos opciones.
1) compartir lo mismo FileStream
con las funciones de sincronización adecuadas (porque no es seguro para subprocesos ). Vea esta y esta publicaciones para ver un ejemplo.
2) utilice FileShare
la enumeración para indicarle al sistema operativo que permita que otros procesos (u otras partes de su propio proceso) accedan al mismo archivo al mismo tiempo.
using (var stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.Read))
{
}
En este ejemplo, mostré cómo abrir un archivo para escribirlo y compartirlo para leerlo; tenga en cuenta que cuando la lectura y la escritura se superponen, se obtienen datos indefinidos o no válidos. Es una situación que debe manejarse al leer. También tenga en cuenta que esto no hace que el acceso al stream
subproceso sea seguro, por lo que este objeto no se puede compartir con varios subprocesos a menos que el acceso esté sincronizado de alguna manera (consulte los enlaces anteriores). Hay otras opciones para compartir disponibles que abren escenarios más complejos. Consulte MSDN para obtener más detalles.
En general, N procesos pueden leer del mismo archivo todos juntos, pero solo uno debe escribir; en un escenario controlado, incluso puede habilitar escrituras simultáneas, pero esto no se puede generalizar en unos pocos párrafos de texto dentro de esta respuesta.
¿ Es posible desbloquear un archivo utilizado por otro proceso? No siempre es seguro ni tan fácil, pero sí, es posible .
El uso de FileShare solucionó mi problema al abrir un archivo incluso si lo abre otro proceso.
using (var stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.ReadWrite))
{
}