¿Cómo se puede verificar fácilmente si se deniega el acceso a un archivo en .NET?

Básicamente, me gustaría verificar si tengo derechos para abrir el archivo antes de tratar de abrirlo; No quiero usar un try / catch para esta verificación a menos que sea necesario. ¿Hay alguna propiedad de acceso a archivos que pueda verificar de antemano?

Lo he hecho innumerables veces en el pasado, y casi cada vez que lo hago me equivoqué al intentarlo.

Los permisos de archivos (incluso la existencia de archivos) son volátiles ; pueden cambiar en cualquier momento. Gracias a la Ley de Murphy, esto incluye especialmente el breve período entre el momento en que revisas el archivo y cuando intentas abrirlo. Un cambio es aún más probable si se encuentra en un área donde sabe que necesita verificar primero. Sin embargo, curiosamente, nunca sucederá en sus entornos de prueba o desarrollo, que tienden a ser bastante estáticos. Esto hace que el problema sea más difícil de rastrear más tarde y facilita que este tipo de error lo produzca.

Lo que esto significa es que todavía debe ser capaz de manejar la excepción si los permisos de archivo o la existencia son malos, a pesar de su verificación. Se requiere el código de manejo de excepciones, ya sea que compruebe o no los permisos del archivo por adelantado. El código de manejo de excepciones proporciona toda la funcionalidad de las comprobaciones de existencia o permisos. Además, aunque se sabe que los manejadores de excepciones como este son lentos, es importante recordar que el disco E / S es incluso más lento … mucho más lento … y llamar a la función .Exists () o verificar los permisos forzará un viaje adicional fuera del sistema de archivos.

En resumen, una comprobación inicial antes de intentar abrir el archivo es redundante y derrochador. No existe un beneficio adicional sobre el manejo de excepciones, en realidad perjudicará, no ayudará, su rendimiento, agrega costos en términos de más código que debe mantenerse y puede introducir errores sutiles en su código. Simplemente no hay ninguna ventaja para hacer el control inicial. En cambio, lo correcto aquí es simplemente tratar de abrir el archivo y poner su esfuerzo en un buen manejador de excepciones si falla. Lo mismo es cierto incluso si solo está comprobando si el archivo existe o no. Este razonamiento se aplica a cualquier recurso volátil.

Consejo rápido para cualquier persona que venga con un problema similar:

Tenga cuidado con las aplicaciones de sincronización web como DropBox. Acabo de pasar 2 horas pensando que la statement “usar” (patrón de eliminación) está rota en .NET.

Finalmente me di cuenta de que Dropbox continuamente lee y escribe archivos en segundo plano, para sincronizarlos.

¿Adivina dónde se encuentra mi carpeta de proyectos de Visual Studio? Dentro de la carpeta “Mi Dropbox”, por supuesto.

Por lo tanto, cuando ejecuté mi aplicación en el modo de depuración, los archivos que estaba leyendo y escribiendo también fueron continuamente accedidos por DropBox para ser sincronizados con el servidor DropBox. Esto causó los conflictos de locking / acceso.

Así que al menos ahora sé que necesito una función File Open más robusta (es decir, TryOpen () que hará múltiples bashs). Me sorprende que no sea una parte incorporada del marco.

[Actualizar]

Aquí está mi función de ayudante:

///  /// Tries to open a file, with a user defined number of attempt and Sleep delay between attempts. ///  /// The full file path to be opened /// Required file mode enum value(see MSDN documentation) /// Required file access enum value(see MSDN documentation) /// Required file share enum value(see MSDN documentation) /// The total number of attempts to make (multiply by attemptWaitMS for the maximum time the function with Try opening the file) /// The delay in Milliseconds between each attempt. /// A valid FileStream object for the opened file, or null if the File could not be opened after the required attempts public FileStream TryOpen(string filePath, FileMode fileMode, FileAccess fileAccess,FileShare fileShare,int maximumAttempts,int attemptWaitMS) { FileStream fs = null; int attempts = 0; // Loop allow multiple attempts while (true) { try { fs = File.Open(filePath, fileMode, fileAccess, fileShare); //If we get here, the File.Open succeeded, so break out of the loop and return the FileStream break; } catch (IOException ioEx) { // IOExcception is thrown if the file is in use by another process. // Check the numbere of attempts to ensure no infinite loop attempts++; if (attempts > maximumAttempts) { // Too many attempts,cannot Open File, break and return null fs = null; break; } else { // Sleep before making another attempt Thread.Sleep(attemptWaitMS); } } } // Reutn the filestream, may be valid or null return fs; } 

Primero, lo que dijo Joel Coehoorn.

Además, debe examinar las suposiciones que subyacen a su deseo de evitar el uso de prueba / captura a menos que sea necesario. La razón típica para evitar la lógica que depende de las excepciones (la creación de objetos de Exception tiene un rendimiento deficiente) probablemente no sea relevante para el código que abre un archivo.

Supongo que si está escribiendo un método que rellena una List abriendo todos los archivos en un subárbol de directorio y esperaba que no se pudiera acceder a un gran número de ellos, es posible que desee verificar los permisos de archivo antes de intentar abrir un archivo para que no recibiste demasiadas excepciones. Pero aún manejarías la excepción. Además, probablemente haya algo terriblemente incorrecto en el diseño de tu progtwig si estás escribiendo un método que hace esto.

Aquí está la solución que está buscando

 var fileIOPermission = new FileIOPermission(FileIOPermissionAccess.Read, System.Security.AccessControl.AccessControlActions.View, MyPath); if (fileIOPermission.AllFiles == FileIOPermissionAccess.Read) { // Do your thing here... } 

esto crea un nuevo permiso de lectura basado en la vista para la ruta de todos los archivos y luego verifica si es igual a la lectura de acceso a archivos.

 public static FileStream GetFileStream(String filePath, FileMode fileMode, FileAccess fileAccess, FileShare fileShare, ref int attempts, int attemptWaitInMilliseconds) { try { return File.Open(filePath, fileMode, fileAccess, fileShare); } catch (UnauthorizedAccessException unauthorizedAccessException) { if (attempts <= 0) { throw unauthorizedAccessException; } else { Thread.Sleep(attemptWaitInMilliseconds); attempts--; return GetFileStream(filePath, fileMode, fileAccess, fileShare, ref attempts, attemptWaitInMilliseconds); } } }