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 está funcionando rápidamente, intentará acceder al archivo antes de que se guarde nuevamente 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 todos mis Google solo han dado lugar a la creación de controles 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.
Respuestas:
NOTA actualizada sobre esta solución : la verificación con
FileAccess.ReadWrite
fallará para los archivos de solo lectura, por lo que la solución se ha modificado para verificar conFileAccess.Read
. Si bien esta solución funciona porque al intentar verificarFileAccess.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 acceso FileShare.Read 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:
fuente
public static bool IsLocked(this FileInfo file) {/*...*/}
.Puede sufrir una condición de carrera de hilo en esto, que hay ejemplos documentados de que esto se utiliza como una vulnerabilidad de seguridad. Si comprueba que el archivo está disponible, pero luego intenta usarlo, podría lanzarlo en ese punto, que un usuario malintencionado podría usar para forzar y explotar su código.
Su mejor opción es intentar capturar / finalmente, que intenta obtener el identificador de archivo.
fuente
Use esto para verificar si un archivo está bloqueado:
Por razones de rendimiento, le recomiendo que lea el contenido del archivo en la misma operación. Aquí hay unos ejemplos:
Pruébalo tú mismo:
fuente
IOException
, en lugar de generalException
y luego una prueba de tipo.IOException
después del general. El general atrapará todo lo que pasa y el específicoIOException
siempre estará solo. Solo intercambia los dos.Solo use la excepción según lo previsto. Acepte que el archivo está en uso e intente nuevamente, varias veces hasta que se complete su acción. Este también es el más eficiente porque no desperdicia ningún ciclo verificando el estado antes de actuar.
Use la función a continuación, por ejemplo
Método reutilizable que agota el tiempo de espera después de 2 segundos.
fuente
Quizás podría usar un FileSystemWatcher y observar el evento Modificado.
No lo he usado yo mismo, pero podría valer la pena intentarlo. Si el sistema de archivos resulta ser un poco pesado para este caso, iría al bucle try / catch / sleep.
fuente
Puede devolver una tarea que le proporciona una secuencia tan pronto como esté disponible. Es una solución simplificada, pero es un buen punto de partida. Es seguro para hilos.
Puede usar esta transmisión como de costumbre:
fuente
GetStreamAsync()
?Lo único que sé es utilizar 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 para probar / atrapar / dormir bucles.
fuente
¡Espero que esto ayude!
fuente
Las respuestas aceptadas anteriormente sufren un problema en el que si el archivo se abrió 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 (como también es cierto para la solución aceptada):
Teniendo en cuenta lo anterior, esto verifica si el archivo está bloqueado para escritura o bloqueado para evitar la lectura :
fuente
Además de trabajar 3 líneas y solo como referencia: si desea la información completa , 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:
Funciona conectándose a la "Reiniciar sesión del administrador".
Podría estar un poco diseñado para sus necesidades particulares ... Pero si eso es lo que desea, continúe y tome el proyecto vs.
fuente
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 de esta manera, puede usar el truco que se explica en la respuesta de Jeremy Thompson. Sin embargo, si intentas hacer esto en muchos archivos (por ejemplo, cuando escribes un instalador), te dolerá un poco.
Una manera muy elegante de resolver esto es usando el hecho de que su sistema de archivos no le permitirá cambiar el nombre de una carpeta si se está usando uno de los archivos. Mantenga la carpeta en el mismo sistema de archivos y funcionará como un encanto.
Tenga en cuenta que debe tener en cuenta las formas obvias de explotar esto. Después de todo, los archivos no serán bloqueados. Además, tenga en cuenta que hay otras razones que pueden provocar que su
Move
operación falle. Obviamente, el manejo adecuado de errores (MSDN) puede ayudar aquí.Para archivos individuales, me quedaría con la sugerencia de bloqueo publicada por Jeremy Thompson.
fuente
FileShare
y la comprobación de un bloqueo.Aquí hay un código que, por lo que puedo decir mejor, hace lo mismo que la respuesta aceptada pero con menos código:
Sin embargo, creo que es más robusto hacerlo de la siguiente manera:
fuente
Puede usar mi biblioteca para acceder a archivos desde múltiples aplicaciones.
Puede instalarlo desde nuget: Install-Package Xabe.FileLock
Si desea obtener más información al respecto, consulte https://github.com/tomaszzmuda/Xabe.FileLock
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.
fuente
Una vez necesitaba subir archivos PDF a 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 apuro, intenté algunas de las principales respuestas en este hilo, pero no pude hacer que funcionaran. Lo que funcionó para mí fue tratar de 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, ya que 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.
fuente
Estoy interesado en ver si esto desencadena algún reflejo de WTF. Tengo un proceso que crea y luego 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. Este fue un hecho bastante frecuente porque los nombres de los archivos se basan en números de cotizaciones de ventas.
En lugar de fallar de una manera tan desagradable, decidí confiar en el versionado automático de archivos:
Probablemente se pueda prestar más atención al
catch
bloque para asegurarme de que estoy captando las IOException (s) correctas. Probablemente también borre 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 fue el problema que estaba tratando de resolver cuando llegué aquí, por lo que tal vez sea útil para otra persona.
fuente
¿Algo como esto ayudaría?
fuente
Intente mover / copiar el archivo a un directorio temporal. Si puede, no tiene bloqueo y puede trabajar de forma segura en el directorio temporal sin obtener bloqueos. De lo contrario, intenta moverlo nuevamente en x segundos.
fuente
Utilizo esta solución, pero tengo un intervalo de tiempo entre cuando verifico el bloqueo del archivo con la función IsFileLocked y cuando abro el archivo. En este intervalo 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:
¿Qué piensas? ¿Puedo cambiar algo? ¿Quizás no tuve que usar la función IsFileBeingUsed en absoluto?
Gracias
fuente