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?¿cómo se puede verificar fácilmente si se deniega el acceso para un archivo en .NET?
Respuesta
Lo he hecho innumerables veces en el pasado, y casi cada vez que lo he hecho me equivoqué al intentarlo.
Los permisos de archivos (incluso existencia del archivo) son volátiles — pueden cambiar en cualquier momento. Gracias a la Ley de Murphy, este especialmente incluye el breve período entre el momento en que revisa el archivo y cuando intenta 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 tiene que ser capaz de manejar la excepción si los permisos de archivo o existencia son malos, a pesar de su verificación. El código de manejo de excepciones es requerido, ya sea que compruebe o no los permisos del archivo por adelantado. El código de manejo de excepciones proporciona todos de la funcionalidad de existencia o controles de permisos. Además, aunque se sabe que los manejadores de excepciones como este son lentos, es importante recordar que el disco de E/S es incluso más lento ... un lote más lento ... y llamar a la función .Exists() o verificar los permisos forzará una viaje adicional al 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.
Eric Lippert probablemente explica por qué Joel es correcto here
Jeje, lo leí hace un tiempo y también estaba pensando en esta publicación exacta, porque esta es exactamente una molesta excepción. Pero todavía estamos esperando un método File.TryOpen() incorporado, e incluso entonces puede que tenga que tener cuidado si permite el acceso compartido suficiente. –
En primer lugar, lo que dijo Joel Coehoorn.
También: debe examinar las suposiciones que subyacen a su deseo de evitar el uso de try/catch a menos que sea necesario. La razón típica para evitar la lógica que depende de las excepciones (crear objetos Exception
tiene un bajo rendimiento) probablemente no sea relevante para el código que abre un archivo.
Supongo que si está escribiendo un método que rellena un archivo List<FileStream>
abriendo todos los archivos en un subárbol de directorio y esperaba que no se pudiera acceder a un gran número de ellos, debería verificar los permisos de archivo antes de intentar abrir un archivo 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 programa si estás escribiendo un método que hace esto.
Consejo rápido para cualquier otra persona que viene aquí con un problema similar:
Cuidado con aplicaciones de sincronización web, tales como DropBox. Acabo de pasar 2 horas pensando que la declaración "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 Proyectos de Visual Studio? Dentro de la carpeta "Mi Dropbox", por supuesto.
Por lo tanto, al ejecutar mi aplicación en modo Depuración, los archivos que estaba leyendo y escribiendo también fueron accedidos continuamente por DropBox para ser sincronizados con el servidor DropBox. Esto causó los conflictos de bloqueo/acceso.
Por lo menos ahora sé que necesito una función File Open más robusta (es decir, TryOpen() que hará múltiples intentos). Me sorprende que no sea una parte incorporada del marco.
[Actualización]
Aquí es mi función auxiliar:
/// <summary>
/// Tries to open a file, with a user defined number of attempt and Sleep delay between attempts.
/// </summary>
/// <param name="filePath">The full file path to be opened</param>
/// <param name="fileMode">Required file mode enum value(see MSDN documentation)</param>
/// <param name="fileAccess">Required file access enum value(see MSDN documentation)</param>
/// <param name="fileShare">Required file share enum value(see MSDN documentation)</param>
/// <param name="maximumAttempts">The total number of attempts to make (multiply by attemptWaitMS for the maximum time the function with Try opening the file)</param>
/// <param name="attemptWaitMS">The delay in Milliseconds between each attempt.</param>
/// <returns>A valid FileStream object for the opened file, or null if the File could not be opened after the required attempts</returns>
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;
}
@Ash Creo que no leyó la pregunta correctamente ÉL quiere evitar intentar capturar. – Ravisha
@ Ravisha, ¿has leído la respuesta más votado de Joel? Como dice Joel, ** "Lo que debes hacer es intentar abrir el archivo y manejar la excepción si falla" **. Por favor, no menosprecie solo porque no le gusta el hecho de que algo no se puede evitar. – Ash
¡Gracias por el código! Una cosa, podría ser mejor usar usando, p. ver [la respuesta de Tazeem aquí] (http://social.msdn.microsoft.com/Forums/en/netfxbcl/thread/e99a7cea-43d3-49b1-82bc-5669e0b9d052) – Cel
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);
}
}
}
-1: use "throw"; no "throw desautorizadaAccessException;". Estás perdiendo tu rastro de pila. –
¿Por qué se pasan los "intentos" por ref? Eso no tiene sentido. Tampoco prueba para '<=' en lugar de simplemente '=='. –
@John: bueno, en este caso es * deseable * perder el rastro de pila (profundamente anidado) de la llamada recursiva, así que creo que en este caso 'throw ex' es en realidad * lo correcto * por hacer. –
Aquí está la solución que busca
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 ver la ruta de todos los archivos y luego verifica si es igual a la lectura de acceso a archivos.
Este código da falsos negativos en los directorios – Conrad
- 1. Falló publicación de Visual Studio: "No se puede eliminar el archivo ... Se deniega el acceso a la ruta ...".
- 2. No se puede copiar el archivo al servidor en la compilación. Se deniega el acceso a la ruta
- 3. ¿Cómo verificar si __PRETTY_FUNCTION__ se puede usar?
- 4. ASP.NET + Se deniega el acceso a la ruta
- 5. ¿Cómo se puede detectar fácilmente si 2 ROI se cruzan en OpenCv?
- 6. ¿Cómo verificar si se puede crear un archivo dentro del directorio dado en MS XP/Vista?
- 7. cómo verificar si un archivo se selecciona usando javascript?
- 8. ¿Cómo se puede "verificar" el código?
- 9. ¿Cómo sondear el directorio para verificar si se agrega un nuevo archivo?
- 10. ¿Cómo se puede sincronizar fácilmente un bloque de código C#?
- 11. file_put_contents diciendo que se deniega el permiso?
- 12. Se puede configurar .NET OpenFileDialog para que el usuario pueda seleccionar un archivo .lnk
- 13. ¿Cómo verificar si la lista se puede ordenar?
- 14. ¿Cómo puedo verificar si un evento se ha suscrito a, en .NET?
- 15. ¿Cómo se puede saber si un archivo se almacena en caché en la memoria en Linux?
- 16. SerializationException en 'CustomIdentity' cuando se deniega el usuario en ASP.NET
- 17. ¿Cómo se puede saber si el iPhone se bloquea?
- 18. Verificar/Verificar para ver si se ha instalado un Perfil de configuración en el iPhone
- 19. ¿Se deniega el acceso al intentar crear FileFileAsync en InstalledLocation StorageFolder?
- 20. Contenido HTML5 ¿Se puede verificar si el formato se aplica con execCommand?
- 21. ¿Cómo se puede ejecutar el objetivo CMake si se modificó el archivo especificado?
- 22. ¿cómo puedo verificar si existe un archivo?
- 23. Compruebe si se escanea un archivo PDF
- 24. ¿Cómo puedo verificar si existe un archivo en Perl?
- 25. ¿Cómo se puede verificar si un elemento pertenece a un subtipo u otro?
- 26. ¿Cómo verificar si el servidor X se está ejecutando?
- 27. Error al implementar la aplicación BizTalk: se deniega el acceso. (Excepción de HRESULT: 0x80070005 (E_ACCESSDENIED))
- 28. Se deniega el acceso a la ruta 'c: \ inetpub \ wwwroot \ myapp \ App_Data'
- 29. ¿Cómo verificar si un proceso se está ejecutando con Delphi?
- 30. ¿Cómo puedo verificar si actualmente se está visualizando un UIViewController?
Título cuando cambié la etiqueta: "estoy corrigiendo". No es broma. –
De acuerdo, me gustaría que hubiera un TryOpen (es decir, el patrón Try-Parse). – Tristan