¿Hay alguna forma de comprobar si un archivo está en uso?

Estoy escribiendo un programa en C # que necesita acceder repetidamente a 1 archivo de imagen. La mayoría de las veces funciona, pero si mi computadora funciona rápido, intentará acceder al archivo antes de que se guarde de nuevo en el sistema de archivos y arrojará un error:

"Archivo en uso por otro proceso"

Me gustaría encontrar una forma de evitar esto, pero toda mi búsqueda en Google solo ha producido la creación de comprobaciones mediante el manejo de excepciones. Esto va en contra de mi religión, así que me preguntaba si alguien tiene una mejor manera de hacerlo.

preguntado el 18 de mayo de 09 a las 03:05

De acuerdo, puede probarlo examinando todas las manijas abiertas del sistema. Sin embargo, dado que Windows es un sistema operativo multitarea, existe la posibilidad de que, justo después de ejecutar el código para determinar si el archivo está abierto y considera que no lo está, un código de proceso comience a usar ese archivo, luego, cuando intente utilícelo, recibirá un error. Pero no hay nada de malo en verificar primero; simplemente no asuma que no está en uso cuando realmente lo necesita. -

Pero solo para este tema específico; Recomendaría no examinar los identificadores de archivo y simplemente intentar algunas veces preestablecidas, digamos 3-5 antes de fallar. -

¿Cómo se genera este archivo de imagen? ¿Puede detener / dormir / pausar su programa hasta que se complete la generación? Esa es, con mucho, una forma superior de manejar la situación. Si no es así, no creo que pueda evitar usar el manejo de excepciones. -

¿No es todo uso de excepciones una verificación de alguna suposición al hacer algo potencialmente peligroso sin descartar deliberadamente la posibilidad de falla? -

Tu filosofía tiene una mala comprensión de las excepciones. La mayoría de la gente piensa que las excepciones significan que algo está mal, muere, muere, muere. Cuando excepción significa ... excepción. Significa que ocurrió algo excepcional que debe "manejar" (o tener en cuenta). Tal vez desee seguir intentando acceder a los datos, tal vez el usuario necesite saber que no puede obtener una conexión. ¿A qué te dedicas? Usted maneja la ConnectionFailedException y notifica al usuario, así que tal vez, dejen de intentarlo después de una hora y noten que el cable está desconectado. -

19 Respuestas

NOTA actualizada sobre esta solución: Consultando con FileAccess.ReadWrite fallará para archivos de solo lectura, por lo que la solución se ha modificado para verificar con FileAccess.Read. Si bien esta solución funciona porque tratando de verificar con FileAccess.Read fallará si el archivo tiene un bloqueo de escritura o lectura, sin embargo, esta solución no funcionará si el archivo no tiene un bloqueo de escritura o lectura, es decir, se ha abierto (para leer o escribir) con FileShare. Acceso de lectura o FileShare.Write.

ORIGINAL: He usado este código durante los últimos años y no he tenido ningún problema con él.

Comprenda sus dudas sobre el uso de excepciones, pero no puede evitarlas todo el tiempo:

protected virtual bool IsFileLocked(FileInfo file)
{
    try
    {
        using(FileStream stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None))
        {
            stream.Close();
        }
    }
    catch (IOException)
    {
        //the file is unavailable because it is:
        //still being written to
        //or being processed by another thread
        //or does not exist (has already been processed)
        return true;
    }

    //file is not locked
    return false;
}

respondido 07 nov., 19:17

Esta es una gran solución, pero tengo un comentario: es posible que no desee abrir el archivo con el modo de acceso FileAccess. Lee, ya que ReadWrite siempre fallará si el archivo es de solo lectura. - adeel825

-1. Esta es una respuesta deficiente, porque el archivo podría bloquearse por otro hilo / proceso después de que se cierre en IsFileLocked, y antes de que su hilo tenga la oportunidad de abrirlo. - Polifun

Creo que esta es una gran respuesta. Estoy usando esto como un método de extensión a la public static bool IsLocked(this FileInfo file) {/*...*/}. - manuzor

@ChrisW: es posible que se esté preguntando qué está pasando. No se alarme. Estás sujeto a la ira de la comunidad de Daily WTF: thedailywtf.com/Comentarios/… - pierre lebeaupin

@ChrisW ¿Por qué eso es algo malo? Esta comunidad está aquí para señalar buenas y malas respuestas. Si un grupo de profesionales notan que esto es algo malo y se unen para votar negativamente, entonces el sitio es WAI. Y antes de que te pongas negativo, si lees ese artículo, te dicen que "vote a favor la respuesta correcta" y no a la incorrecta. ¿Quieres que también expliquen sus votos a favor en los comentarios? ¡Gracias por presentarme otro buen sitio! - Lee Louviere

Puede sufrir una condición de carrera de subprocesos por lo que hay ejemplos documentados de que se utiliza como una vulnerabilidad de seguridad. Si comprueba que el archivo está disponible, pero luego intenta usarlo, podría arrojarlo en ese punto, que un usuario malintencionado podría usar para forzar y explotar su código.

Su mejor apuesta es intentar atrapar / finalmente que intenta obtener el identificador del archivo.

try
{
   using (Stream stream = new FileStream("MyFilename.txt", FileMode.Open))
   {
        // File/Stream manipulating code here
   }
} catch {
  //check here why it failed and ask user to retry if the file is in use.
}

respondido 12 mar '13, 16:03

+1. No existe una forma 100% segura de "saber si un archivo está en uso" porque milisegundos después de realizar la verificación, es posible que el archivo ya no esté en uso, o viceversa. En su lugar, simplemente abra el archivo y utilícelo si no hay excepciones. - Sedat Kapanoglu

Lástima que .NET no es compatible con CAS. Algo como TryOpenFile (Ref FileHandle) que devuelve éxito / fracaso. Siempre debe haber una solución alternativa que no dependa únicamente del manejo de excepciones. Me pregunto cómo lo hace Microsoft Office. - TamusJRoyce

La clave para entender aquí es que esta API simplemente usa la API de Windows para obtener un identificador de archivo. Como tal, necesitan traducir el código de error recibido de la API de C y ajustarlo a una excepción para lanzar. Tenemos manejo de excepciones en .Net, así que ¿por qué no usarlo? De esa manera, puede escribir una ruta de avance limpia en su código y dejar el manejo de errores en una ruta de código separada. - Spence

La declaración de uso es para garantizar que la transmisión se cierre después de que termine. Creo que encontrará que using () {} tiene menos caracteres que try {} finalmente {obj.Dispose ()}. También encontrará que ahora necesita declarar la referencia de su objeto fuera de la instrucción using, que es más tipeo. Si tiene una interfaz explícita, también tendrá que transmitir. Finalmente, desea eliminar lo antes posible, y la lógica finalmente puede tener una interfaz de usuario o cualquier otra acción de ejecución prolongada que tenga poco que ver con la llamada a IDispose. - Spence

eso no niega el hecho de que tienes que declarar tu objeto fuera del intento y tienes que llamar explícitamente a dispose, que el uso hace por ti y significa lo mismo. - Spence

Use esto para verificar si un archivo está bloqueado:

using System.IO;
using System.Runtime.InteropServices;
internal static class Helper
{
const int ERROR_SHARING_VIOLATION = 32;
const int ERROR_LOCK_VIOLATION = 33;

private static bool IsFileLocked(Exception exception)
{
    int errorCode = Marshal.GetHRForException(exception) & ((1 << 16) - 1);
    return errorCode == ERROR_SHARING_VIOLATION || errorCode == ERROR_LOCK_VIOLATION;
}

internal static bool CanReadFile(string filePath)
{
    //Try-Catch so we dont crash the program and can check the exception
    try {
        //The "using" is important because FileStream implements IDisposable and
        //"using" will avoid a heap exhaustion situation when too many handles  
        //are left undisposed.
        using (FileStream fileStream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) {
            if (fileStream != null) fileStream.Close();  //This line is me being overly cautious, fileStream will never be null unless an exception occurs... and I know the "using" does it but its helpful to be explicit - especially when we encounter errors - at least for me anyway!
        }
    }
    catch (IOException ex) {
        //THE FUNKY MAGIC - TO SEE IF THIS FILE REALLY IS LOCKED!!!
        if (IsFileLocked(ex)) {
            // do something, eg File.Copy or present the user with a MsgBox - I do not recommend Killing the process that is locking the file
            return false;
        }
    }
    finally
    { }
    return true;
}
}

Por razones de rendimiento, le recomiendo que lea el contenido del archivo en la misma operación. Aquí hay unos ejemplos:

public static byte[] ReadFileBytes(string filePath)
{
    byte[] buffer = null;
    try
    {
        using (FileStream fileStream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
        {
            int length = (int)fileStream.Length;  // get file length
            buffer = new byte[length];            // create buffer
            int count;                            // actual number of bytes read
            int sum = 0;                          // total number of bytes read

            // read until Read method returns 0 (end of the stream has been reached)
            while ((count = fileStream.Read(buffer, sum, length - sum)) > 0)
                sum += count;  // sum is a buffer offset for next reading

            fileStream.Close(); //This is not needed, just me being paranoid and explicitly releasing resources ASAP
        }
    }
    catch (IOException ex)
    {
        //THE FUNKY MAGIC - TO SEE IF THIS FILE REALLY IS LOCKED!!!
        if (IsFileLocked(ex))
        {
            // do something? 
        }
    }
    catch (Exception ex)
    {
    }
    finally
    {
    }
    return buffer;
}

public static string ReadFileTextWithEncoding(string filePath)
{
    string fileContents = string.Empty;
    byte[] buffer;
    try
    {
        using (FileStream fileStream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
        {
            int length = (int)fileStream.Length;  // get file length
            buffer = new byte[length];            // create buffer
            int count;                            // actual number of bytes read
            int sum = 0;                          // total number of bytes read

            // read until Read method returns 0 (end of the stream has been reached)
            while ((count = fileStream.Read(buffer, sum, length - sum)) > 0)
            {
                sum += count;  // sum is a buffer offset for next reading
            }

            fileStream.Close(); //Again - this is not needed, just me being paranoid and explicitly releasing resources ASAP

            //Depending on the encoding you wish to use - I'll leave that up to you
            fileContents = System.Text.Encoding.Default.GetString(buffer);
        }
    }
    catch (IOException ex)
    {
        //THE FUNKY MAGIC - TO SEE IF THIS FILE REALLY IS LOCKED!!!
        if (IsFileLocked(ex))
        {
            // do something? 
        }
    }
    catch (Exception ex)
    {
    }
    finally
    { }     
    return fileContents;
}

public static string ReadFileTextNoEncoding(string filePath)
{
    string fileContents = string.Empty;
    byte[] buffer;
    try
    {
        using (FileStream fileStream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
        {
            int length = (int)fileStream.Length;  // get file length
            buffer = new byte[length];            // create buffer
            int count;                            // actual number of bytes read
            int sum = 0;                          // total number of bytes read

            // read until Read method returns 0 (end of the stream has been reached)
            while ((count = fileStream.Read(buffer, sum, length - sum)) > 0) 
            {
                sum += count;  // sum is a buffer offset for next reading
            }

            fileStream.Close(); //Again - this is not needed, just me being paranoid and explicitly releasing resources ASAP

            char[] chars = new char[buffer.Length / sizeof(char) + 1];
            System.Buffer.BlockCopy(buffer, 0, chars, 0, buffer.Length);
            fileContents = new string(chars);
        }
    }
    catch (IOException ex)
    {
        //THE FUNKY MAGIC - TO SEE IF THIS FILE REALLY IS LOCKED!!!
        if (IsFileLocked(ex))
        {
            // do something? 
        }
    }
    catch (Exception ex)
    {
    }
    finally
    {
    }

    return fileContents;
}

Pruébelo usted mismo:

byte[] output1 = Helper.ReadFileBytes(@"c:\temp\test.txt");
string output2 = Helper.ReadFileTextWithEncoding(@"c:\temp\test.txt");
string output3 = Helper.ReadFileTextNoEncoding(@"c:\temp\test.txt");

Respondido 20 Abr '15, 08:04

Votaría si no hubiera tantos "números mágicos" allí en.wikipedia.org/wiki/Magic_number_(programación) - Kris

Me refería a las comparaciones de errorCode, no a los cambios de bits. aunque ahora lo mencionas ... - Kris

Tu captura debe estar encendida IOException, en lugar de en general Exception y luego una prueba de tipo. - Askolein

@JeremyThompson lamentablemente le pones el específico IOException después del general. El general captará todo lo que pasa y el específico IOException siempre estarás solo. Simplemente intercambie los dos. - Askolein

Me gusta esta solucion. Otra sugerencia: dentro de la captura como otra cosa para el if (IsFileLocked (ex)) arrojaría ex. Esto luego manejará el caso donde el archivo no existe (o cualquier otra IOException) lanzando la excepción. - shindigo

Quizás le vendría bien un Observador del sistema de archivos y esté atento al evento Cambiado.

No lo he usado yo mismo, pero podría valer la pena intentarlo. Si el observador del sistema de archivos resulta ser un poco pesado para este caso, optaría por el bucle try / catch / sleep.

contestado el 18 de mayo de 09 a las 07:05

El uso de FileSystemWatcher no ayuda, porque los eventos Created y Changed surgen al comienzo de la creación / cambio de un archivo. Incluso los archivos pequeños necesitan más tiempo para ser escritos y cerrados por el sistema operativo que la aplicación .NET necesita para ejecutarse a través de FileSystemEventHandler Callback. Esto es muy triste, pero no hay otra opción que estimar el tiempo de espera antes de acceder al archivo o encontrarse con bucles de excepción ... - user219337

Sin embargo, FileSystemWatcher no maneja muy bien muchos cambios al mismo tiempo, así que tenga cuidado con eso. - Ben F.

Por cierto, ¿se han dado cuenta, mientras depuraban y veían hilos, que MS llama a su propio FSW "FileSystemWather"? ¿Qué es un agua de todos modos? - Devlord

Precisamente tuve este problema porque un servicio de Windows con FileSystemWatcher intentó leer el archivo antes de que el proceso lo cerrara. - desarrollador libre

Simplemente use la excepción según lo previsto. Acepte que el archivo está en uso e inténtelo de nuevo, repetidamente hasta que se complete su acción. Este también es el más eficiente porque no desperdicia ningún ciclo revisando el estado antes de actuar.

Utilice la función siguiente, por ejemplo

TimeoutFileAction(() => { System.IO.File.etc...; return null; } );

Método reutilizable que se agota después de 2 segundos

private T TimeoutFileAction<T>(Func<T> func)
{
    var started = DateTime.UtcNow;
    while ((DateTime.UtcNow - started).TotalMilliseconds < 2000)
    {
        try
        {
            return func();                    
        }
        catch (System.IO.IOException exception)
        {
            //ignore, or log somewhere if you want to
        }
    }
    return default(T);
}

contestado el 26 de mayo de 15 a las 16:05

Puede devolver una tarea que le proporciona una transmisión tan pronto como esté disponible. Es una solución simplificada, pero es un buen punto de partida. Es seguro para subprocesos.

private async Task<Stream> GetStreamAsync()
{
    try
    {
        return new FileStream("sample.mp3", FileMode.Open, FileAccess.Write);
    }
    catch (IOException)
    {
        await Task.Delay(TimeSpan.FromSeconds(1));
        return await GetStreamAsync();
    }
}

Puede usar esta transmisión como de costumbre:

using (var stream = await FileStreamGetter.GetStreamAsync())
{
    Console.WriteLine(stream.Length);
}

Respondido 20 Oct 15, 13:10

Cuántos segundos hasta que una pila se desborde de la recursividad en GetStreamAsync()? - Tipo CAD

@CADbloke, ha planteado un muy buen punto. De hecho, mi muestra puede tener una excepción de desbordamiento de pila, en caso de que un archivo no esté disponible durante mucho tiempo. Relacionado con esta respuesta stackoverflow.com/questions/4513438/…, podría generar la excepción en 5 horas. - Iván Branets

En relación con sus casos de uso, es preferible lanzar una excepción de E / S si, digamos, 10 intentos de leer el archivo han fallado. La otra estrategia podría ser aumentar el tiempo de espera por un segundo una vez que se hayan fallado 10 intentos. También puede usar una combinación de ambos. - Iván Branets

Simplemente alertaría (y lo hago) al usuario de que el archivo está bloqueado. Por lo general, lo bloquearon ellos mismos, por lo que probablemente harán algo al respecto. O no. - Tipo CAD

En algunos casos, debe utilizar la política de reintento, ya que es posible que un archivo aún no esté listo. Imagina una aplicación de escritorio para descargar imágenes en alguna carpeta temporal. La aplicación comienza a descargarse y al mismo tiempo abres esta carpeta en el explorador de archivos. Windows quiere crear una miniatura de inmediato y bloquear el archivo. Al mismo tiempo, su aplicación intenta reemplazar la imagen bloqueada en otro lugar. Recibirá una excepción si no usa la política de reintento. - Iván Branets

la única forma que conozco es usar la API de bloqueo exclusiva de Win32 que no es demasiado rápida, pero existen ejemplos.

La mayoría de las personas, para una solución simple a esto, simplemente intentan bucles / atrapar / dormir.

contestado el 18 de mayo de 09 a las 07:05

No puede utilizar esta API sin abrir primero el archivo, momento en el que ya no es necesario. - Harry Johnston

Archivo de Schrodinger. - ElÚltimoGIS

static bool FileInUse(string path)
    {
        try
        {
            using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))
            {
                fs.CanWrite
            }
            return false;
        }
        catch (IOException ex)
        {
            return true;
        }
    }

string filePath = "C:\\Documents And Settings\\yourfilename";
bool isFileInUse;

isFileInUse = FileInUse(filePath);

// Then you can do some checking
if (isFileInUse)
   Console.WriteLine("File is in use");
else
   Console.WriteLine("File is not in use");

¡Espero que esto ayude!

Respondido 22 ago 11, 18:08

La verificación real que realiza está bien; ponerlo dentro de una función es engañoso. NO desea utilizar una función como esta antes de abrir un archivo. Dentro de la función, el archivo se abre, se verifica y se cierra. Luego, el programador ASUME que el archivo TODAVÍA está bien para usar e intenta abrirlo para usarlo. Esto es malo porque podría ser usado y bloqueado por otro proceso que estaba en cola para abrir este archivo. Entre la primera vez que se abrió (para verificar) y la segunda vez que se abrió (para usar), el sistema operativo podría haber desprogramado su proceso y podría estar ejecutando otro proceso. - Lakey

Las respuestas aceptadas anteriores sufren un problema en el que si el archivo se ha abierto para escribir con un modo FileShare.Read o si el archivo tiene un atributo de solo lectura, el código no funcionará. Esta solución modificada funciona de manera más confiable, con dos cosas a tener en cuenta (también es cierto para la solución aceptada):

  1. No funcionará para archivos que se hayan abierto con un modo de escritura compartida.
  2. Esto no tiene en cuenta los problemas de subprocesos, por lo que deberá bloquearlo o manejar los problemas de subprocesos por separado.

Teniendo en cuenta lo anterior, esto verifica si el archivo es bloqueado para escribir or bloqueado para evitar la lectura:

public static bool FileLocked(string FileName)
{
    FileStream fs = null;

    try
    {
        // NOTE: This doesn't handle situations where file is opened for writing by another process but put into write shared mode, it will not throw an exception and won't show it as write locked
        fs = File.Open(FileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None); // If we can't open file for reading and writing then it's locked by another process for writing
    }
    catch (UnauthorizedAccessException) // https://msdn.microsoft.com/en-us/library/y973b725(v=vs.110).aspx
    {
        // This is because the file is Read-Only and we tried to open in ReadWrite mode, now try to open in Read only mode
        try
        {
            fs = File.Open(FileName, FileMode.Open, FileAccess.Read, FileShare.None);
        }
        catch (Exception)
        {
            return true; // This file has been locked, we can't even open it to read
        }
    }
    catch (Exception)
    {
        return true; // This file has been locked
    }
    finally
    {
        if (fs != null)
            fs.Close();
    }
    return false;
}

Respondido 15 Oct 15, 15:10

Todavía tiene el mismo problema que la respuesta aceptada: solo le dice si el archivo fue bloqueado por otro proceso en un momento particular en el tiempo, que no es información útil. Para cuando la función haya devuelto, es posible que el resultado ya esté desactualizado. - Harry Johnston

eso es cierto, uno solo puede verificar en un momento dado (o suscribirse a eventos), la ventaja de este enfoque sobre la solución aceptada es que puede verificar un atributo de solo lectura y un bloqueo de escritura y no devolver un falso positivo. - chico

Aquí hay un código que, por lo que puedo decir, hace lo mismo que la respuesta aceptada pero con menos código:

    public static bool IsFileLocked(string file)
    {
        try
        {
            using (var stream = File.OpenRead(file))
                return false;
        }
        catch (IOException)
        {
            return true;
        }        
    }

Sin embargo, creo que es más robusto hacerlo de la siguiente manera:

    public static void TryToDoWithFileStream(string file, Action<FileStream> action, 
        int count, int msecTimeOut)
    {
        FileStream stream = null;
        for (var i = 0; i < count; ++i)
        {
            try
            {
                stream = File.OpenRead(file);
                break;
            }
            catch (IOException)
            {
                Thread.Sleep(msecTimeOut);
            }
        }
        action(stream);
    }

Respondido 22 ago 16, 21:08

Aparte de trabajar con 3 líneas y solo como referencia: si desea el en toda regla información: hay un pequeño proyecto en Microsoft Dev Center:

https://code.msdn.microsoft.com/windowsapps/How-to-know-the-process-704839f4

De la Introducción:

El código de muestra de C # desarrollado en .NET Framework 4.0 ayudaría a descubrir cuál es el proceso que tiene un bloqueo en un archivo. RmStartSession La función que se incluye en rstrtmgr.dll se ha utilizado para crear una sesión de administrador de reinicio y, según el resultado de la devolución, se crea una nueva instancia del objeto Win32Exception. Después de registrar los recursos en una sesión de Restart Manager a través de RmRegisterRecursos función, RmGetList La función se invoca para comprobar cuáles son las aplicaciones que utilizan un archivo en particular enumerando el RM_PROCESS_INFO formación.

Funciona conectándose a "Reiniciar sesión del administrador".

El Administrador de reinicio usa la lista de recursos registrados con la sesión para determinar qué aplicaciones y servicios deben cerrarse y reiniciarse. Los recursos se pueden identificar por nombres de archivo, nombres cortos de servicios o estructuras RM_UNIQUE_PROCESS que describen aplicaciones en ejecución.

Puede ser un poco sobre Diseñado para sus necesidades particulares ... Pero si eso es lo que quiere, adelante y agarre el vs-project.

Respondido 09 Oct 18, 07:10

Una vez tuve que cargar archivos PDF en un archivo de respaldo en línea. Pero la copia de seguridad fallaría si el usuario tuviera el archivo abierto en otro programa (como un lector de PDF). En mi prisa, intenté algunas de las respuestas principales en este hilo, pero no pude hacer que funcionaran. Lo que funcionó para mí fue intentar mover el archivo PDF a su propio directorio. Descubrí que esto fallaría si el archivo estuviera abierto en otro programa, y ​​si el movimiento fuera exitoso, no se requeriría una operación de restauración como lo haría si se moviera a un directorio separado. Quiero publicar mi solución básica en caso de que pueda ser útil para los casos de uso específicos de otros.

string str_path_and_name = str_path + '\\' + str_filename;
FileInfo fInfo = new FileInfo(str_path_and_name);
bool open_elsewhere = false;
try
{
    fInfo.MoveTo(str_path_and_name);
}
catch (Exception ex)
{
    open_elsewhere = true;
}

if (open_elsewhere)
{
    //handle case
}

Respondido 16 ago 19, 02:08

En mi experiencia, generalmente desea hacer esto, luego 'proteger' sus archivos para hacer algo elegante y luego usar los archivos 'protegidos'. Si solo tiene un archivo que desea usar como este, puede usar el truco que Jeremy Thompson explica en la respuesta. Sin embargo, si intenta hacer esto en muchos archivos (digamos, por ejemplo, cuando está escribiendo un instalador), sufrirá bastante daño.

Una forma muy elegante de resolver esto es utilizando el hecho de que su sistema de archivos no le permitirá cambiar el nombre de una carpeta si uno de los archivos allí se está utilizando. Mantenga la carpeta en el mismo sistema de archivos y funcionará de maravilla.

Tenga en cuenta que debe conocer las formas obvias en que esto se puede explotar. Después de todo, los archivos no se bloquearán. Además, tenga en cuenta que existen otras razones que pueden hacer que su Move operación para fallar. Obviamente, el manejo adecuado de errores (MSDN) puede ayudar aquí.

var originalFolder = @"c:\myHugeCollectionOfFiles"; // your folder name here
var someFolder = Path.Combine(originalFolder, "..", Guid.NewGuid().ToString("N"));

try
{
    Directory.Move(originalFolder, someFolder);

    // Use files
}
catch // TODO: proper exception handling
{
    // Inform user, take action
}
finally
{
    Directory.Move(someFolder, originalFolder);
}

Para archivos individuales, me quedo con la sugerencia de bloqueo publicada por Jeremy Thompson.

respondido 21 nov., 14:11

Hola, Dado que el orden de las respuestas cambia, ¿puedes aclarar qué publicación arriba que quiere decir para los lectores de este popular control de calidad. Gracias. - Jeremy Thompson

@JeremyThompson Tienes razón, gracias, editaré la publicación. Usaría la solución suya, principalmente por su uso correcto de FileShare y comprobar si hay un candado. - atlasto

Puede usar mi biblioteca para acceder a archivos desde múltiples aplicaciones.

Puede instalarlo desde nuget: Install-Package Xabe.FileLock

Si quieres más información al respecto consulta https://github.com/tomaszzmuda/Xabe.FileLock

ILock fileLock = new FileLock(file);
if(fileLock.Acquire(TimeSpan.FromSeconds(15), true))
{
    using(fileLock)
    {
        // file operations here
    }
}

El método fileLock.Acquire devolverá verdadero solo si puede bloquear el archivo exclusivo para este objeto. Pero la aplicación que carga el archivo también debe hacerlo en el bloqueo de archivos. Si el objeto es inaccesible, el método devuelve falso.

Respondido el 07 de Septiembre de 17 a las 11:09

Requiere que todos los procesos que están usando el archivo cooperen. Es poco probable que sea aplicable al problema original de los PO. - Harry Johnston

Estoy interesado en ver si esto desencadena algún reflejo de WTF. Tengo un proceso que crea y posteriormente lanza un documento PDF desde una aplicación de consola. Sin embargo, estaba lidiando con una fragilidad en la que si el usuario ejecutara el proceso varias veces, generando el mismo archivo sin cerrar primero el archivo generado anteriormente, la aplicación lanzaría una excepción y moriría. Esto ocurría con bastante frecuencia porque los nombres de los archivos se basan en números de cotización de ventas.

En lugar de fallar de una manera tan desagradable, decidí confiar en el control de versiones de archivos autoincrementado:

private static string WriteFileToDisk(byte[] data, string fileName, int version = 0)
{
    try
    {
        var versionExtension = version > 0 ? $"_{version:000}" : string.Empty;
        var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{fileName}{versionExtension}.pdf");
        using (var writer = new FileStream(filePath, FileMode.Create))
        {
            writer.Write(data, 0, data.Length);
        }
        return filePath;
    }
    catch (IOException)
    {
        return WriteFileToDisk(data, fileName, ++version);
    }
}

Probablemente se pueda prestar más atención a la catch block para asegurarme de que estoy detectando las IOException correctas. Probablemente también limpiaré el almacenamiento de la aplicación al inicio, ya que estos archivos están destinados a ser temporales de todos modos.

Me doy cuenta de que esto va más allá del alcance de la pregunta del OP de simplemente verificar si el archivo está en uso, pero este era de hecho el problema que estaba buscando resolver cuando llegué aquí, por lo que quizás sea útil para otra persona.

Respondido 05 Abr '18, 13:04

retry_possibility:
//somecode here

try
{
    using(FileStream stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None))
    {
        stream.Close();
    }
    //write or open your file here
}
catch (IOException)
{
    DialogResult dialogResult = MessageBox.Show("This file is opened by you or another user. Please close it and press retry.\n"+ expFilePath, "File Locked", MessageBoxButtons.RetryCancel);
    if (dialogResult == DialogResult.Retry)
    {
        goto retry_possibility;
    }
    else if (dialogResult == DialogResult.Cancel)
    {
        //do nothing
    }
}

Respondido 30 Jul 20, 18:07

¿Algo como esto ayudaría?

var fileWasWrittenSuccessfully = false;
while (fileWasWrittenSuccessfully == false)
{
    try
    {
        lock (new Object())
        {
            using (StreamWriter streamWriter = new StreamWriter("filepath.txt"), true))
            {
                streamWriter.WriteLine("text");
            }
        }

        fileWasWrittenSuccessfully = true;
    }
    catch (Exception)
    {

    }
}

Respondido el 02 de diciembre de 20 a las 22:12

Intente mover / copiar el archivo a un directorio temporal. Si puede, no tiene bloqueo y puede trabajar con seguridad en el directorio temporal sin bloqueos. De lo contrario, intente moverlo de nuevo en x segundos.

contestado el 18 de mayo de 09 a las 10:05

@jcolebrand bloquea ¿qué? el que copiaste? ¿O el que pusiste en el directorio temporal? - cullub

Si copia el archivo, esperando que nadie más esté trabajando en él, y va a usar el archivo temporal, y luego alguien lo bloquea justo después de copiarlo, entonces posiblemente haya perdido datos. - jcolebrand

Utilizo esta solución alternativa, pero tengo un intervalo de tiempo entre el momento en que verifico el bloqueo del archivo con la función IsFileLocked y el momento en que abro el archivo. En este período de tiempo, algún otro hilo puede abrir el archivo, por lo que obtendré IOException.

Entonces, agregué código adicional para esto. En mi caso, quiero cargar XDocument:

        XDocument xDoc = null;

        while (xDoc == null)
        {
            while (IsFileBeingUsed(_interactionXMLPath))
            {
                Logger.WriteMessage(Logger.LogPrioritet.Warning, "Deserialize can not open XML file. is being used by another process. wait...");
                Thread.Sleep(100);
            }
            try
            {
                xDoc = XDocument.Load(_interactionXMLPath);
            }
            catch
            {
                Logger.WriteMessage(Logger.LogPrioritet.Error, "Load working!!!!!");
            }
        }

¿Qué piensas? ¿Puedo cambiar algo? ¿Quizás no tuve que usar la función IsFileBeingUsed en absoluto?

Muchas Gracias

Respondido el 17 de enero de 12 a las 15:01

¿Qué es IsFileBeingUsed? código fuente sobre IsFileBeingUsed? - Kiquenet

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.