UnauthorizedAccessException no puede resolver Directory.GetFiles failure

El método Directory.GetFiles falla en el primer encuentro con una carpeta a la que no tiene derechos de acceso.

El método arroja una excepción de acceso no autorizada (que se puede capturar), pero cuando se hace esto, el método ya ha fallado / terminado.

El código que estoy usando se detalla a continuación:

try { // looks in stated directory and returns the path of all files found getFiles = Directory.GetFiles( @directoryToSearch, filetype, SearchOption.AllDirectories); } catch (UnauthorizedAccessException) { } 

Hasta donde yo sé, no hay forma de verificar de antemano si una determinada carpeta tiene derechos de acceso definidos.

En mi ejemplo, estoy buscando en un disco en una red y cuando encuentro una carpeta de acceso raíz, mi progtwig falla.

Para obtener el control en el nivel que desea, probablemente debería sondear un directorio a la vez, en lugar de un árbol completo. El siguiente método rellena el IList dado con todos los archivos encontrados en el árbol del directorio, excepto aquellos a los que el usuario no tiene acceso:

 // using System.Linq private static void AddFiles(string path, IList files) { try { Directory.GetFiles(path) .ToList() .ForEach(s => files.Add(s)); Directory.GetDirectories(path) .ToList() .ForEach(s => AddFiles(s, files)); } catch (UnauthorizedAccessException ex) { // ok, so we are not allowed to dig into that directory. Move on. } } 

Esta es una mejora de la respuesta de Malcolm (http://stackoverflow.com/a/9831340/226181). Esto escanea todas las unidades lógicas para un patrón de coincidencia de archivos e ignora los directorios que no son accesibles.

  static List SearchFiles(string pattern) { var result = new List(); foreach (string drive in Directory.GetLogicalDrives()) { Console.WriteLine("searching " + drive); var files = FindAccessableFiles(drive, pattern, true); Console.WriteLine(files.Count().ToString() + " files found."); result.AddRange(files); } return result; } private static IEnumerable FindAccessableFiles(string path, string file_pattern, bool recurse) { Console.WriteLine(path); var list = new List(); var required_extension = "mp4"; if (File.Exists(path)) { yield return path; yield break; } if (!Directory.Exists(path)) { yield break; } if (null == file_pattern) file_pattern = "*." + required_extension; var top_directory = new DirectoryInfo(path); // Enumerate the files just in the top directory. IEnumerator files; try { files = top_directory.EnumerateFiles(file_pattern).GetEnumerator(); } catch (Exception ex) { files = null; } while (true) { FileInfo file = null; try { if (files != null && files.MoveNext()) file = files.Current; else break; } catch (UnauthorizedAccessException) { continue; } catch (PathTooLongException) { continue; } yield return file.FullName; } if (!recurse) yield break; IEnumerator dirs; try { dirs = top_directory.EnumerateDirectories("*").GetEnumerator(); } catch (Exception ex) { dirs = null; } while (true) { DirectoryInfo dir = null; try { if (dirs != null && dirs.MoveNext()) dir = dirs.Current; else break; } catch (UnauthorizedAccessException) { continue; } catch (PathTooLongException) { continue; } foreach (var subpath in FindAccessableFiles(dir.FullName, file_pattern, recurse)) yield return subpath; } } 

. Directory.EnumerateFiles de .NET 4 funciona, pero debe tener cuidado al evaluar el enumerable y hacer esa parte dentro del bloque try-catch. El mayor problema es asegurarse de no detener el procesamiento en la primera excepción (que creo que la respuesta https://stackoverflow.com/a/1393219/89584 tiene este problema, corrígeme si me equivoco).

Lo siguiente funciona y te proporciona un Enumerable para que no tengas que evaluar todo el árbol de archivos si estás buscando la primera coincidencia, etc.

 private IEnumerable FindAccessableFiles(string path, string file_pattern, bool recurse) { IEnumerable emptyList = new string[0]; if (File.Exists(path)) return new string[] { path }; if (!Directory.Exists(path)) return emptyList; var top_directory = new DirectoryInfo(path); // Enumerate the files just in the top directory. var files = top_directory.EnumerateFiles(file_pattern); var filesLength = files.Count(); var filesList = Enumerable .Range(0, filesLength) .Select(i => { string filename = null; try { var file = files.ElementAt(i); filename = file.FullName; } catch (UnauthorizedAccessException) { } catch (InvalidOperationException) { // ran out of entries } return filename; }) .Where(i => null != i); if (!recurse) return filesList; var dirs = top_directory.EnumerateDirectories("*"); var dirsLength = dirs.Count(); var dirsList = Enumerable .Range(0, dirsLength) .SelectMany(i => { string dirname = null; try { var dir = dirs.ElementAt(i); dirname = dir.FullName; return FindAccessableFiles(dirname, file_pattern, required_extension, recurse); } catch (UnauthorizedAccessException) { } catch (InvalidOperationException) { // ran out of entries } return emptyList; }) return Enumerable.Concat(filesList, dirsList); } 

mejoras a la bienvenida anterior.

Sé que este hilo es viejo, pero en caso de que alguien se tropiece con esto y necesite una respuesta, tengo una solución recursiva aquí:

 public static List GetAllAccessibleFiles(string rootPath, List alreadyFound = null) { if (alreadyFound == null) alreadyFound = new List(); DirectoryInfo di = new DirectoryInfo(rootPath); var dirs = di.EnumerateDirectories(); foreach (DirectoryInfo dir in dirs) { if (!((dir.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)) { alreadyFound = GetAllAccessibleFiles(dir.FullName, alreadyFound); } } var files = Directory.GetFiles(rootPath); foreach (string s in files) { alreadyFound.Add(s); } return alreadyFound; } 

Devuelve una List contiene la ruta completa a todos los archivos que están en directorios accesibles debajo del directorio raíz dado. Llámalo así:

 var files = GetAllAccessibleFiles(@"C:\myDirectory"); 

Entonces, un resultado podría ser así:

 C:\myDirectory\a\a.txt C:\myDirectory\a\b.mp3 C:\myDirectory\b\a\a\foo.txt C:\myDirectory\b\b\b\hello.exe C:\myDirectory\b\c\bar.jpg C:\myDirectory\and\so\on.bar C:\myDirectory\a_file_in_root.bmp 

Espero que ayude a alguien!

En .NET 4, esto se vuelve mucho más fácil, consulte http://msdn.microsoft.com/en-us/library/dd997370.aspx

 public string[] GetFilesFrom(string dir, string search_pattern, bool recursive) { List files = new List(); string[] temp_files = new string[0]; try { temp_files = Directory.GetFiles(dir, search_pattern, SearchOption.TopDirectoryOnly); } catch { } files.AddRange(temp_files); if (recursive) { string[] temp_dirs = new string[0]; try { temp_dirs = Directory.GetDirectories(dir, search_pattern, SearchOption.TopDirectoryOnly); } catch { } for (int i = 0; i < temp_dirs.Length; i++) files.AddRange(GetFilesFrom(temp_dirs[i], search_pattern, recursive)); } return files.ToArray(); } 

Esta es mi solución para este problema. Simple y a prueba de fallas.

La versión más simple:

 IEnumerable GetAllFiles(string path, string searchPattern) { return System.IO.Directory.EnumerateFiles(path, searchPattern).Union( System.IO.Directory.EnumerateDirectories(path).SelectMany(d => { try { return GetAllFiles(d, searchPattern); } catch (UnauthorizedAccessException e) { return Enumerable.Empty(); } })); }