web-dev-qa-db-fra.com

Ignorer les dossiers / fichiers lorsque Directory.GetFiles () se voit refuser l'accès

J'essaie d'afficher une liste de tous les fichiers trouvés dans le répertoire sélectionné (et éventuellement tous les sous-répertoires). Le problème que j'ai est que lorsque la méthode GetFiles () rencontre un dossier auquel elle ne peut pas accéder, elle lève une exception et le processus s'arrête.

Comment ignorer cette exception (et ignorer le dossier/fichier protégé) et continuer à ajouter des fichiers accessibles à la liste?

try
{
    if (cbSubFolders.Checked == false)
    {
        string[] files = Directory.GetFiles(folderBrowserDialog1.SelectedPath);
        foreach (string fileName in files)
            ProcessFile(fileName);
    }
    else
    {
        string[] files = Directory.GetFiles(folderBrowserDialog1.SelectedPath, "*.*", SearchOption.AllDirectories);
        foreach (string fileName in files)
            ProcessFile(fileName);
    }
    lblNumberOfFilesDisplay.Enabled = true;
}
catch (UnauthorizedAccessException) { }
finally {}
71
Rowan

Vous devrez effectuer la récursivité manuellement; n'utilisez pas AllDirectories - regardez un dossier à la fois, puis essayez d'obtenir les fichiers à partir des sous-répertoires. Non testé, mais quelque chose comme ci-dessous (note utilise un délégué plutôt que de construire un tableau):

using System;
using System.IO;
static class Program
{
    static void Main()
    {
        string path = ""; // TODO
        ApplyAllFiles(path, ProcessFile);
    }
    static void ProcessFile(string path) {/* ... */}
    static void ApplyAllFiles(string folder, Action<string> fileAction)
    {
        foreach (string file in Directory.GetFiles(folder))
        {
            fileAction(file);
        }
        foreach (string subDir in Directory.GetDirectories(folder))
        {
            try
            {
                ApplyAllFiles(subDir, fileAction);
            }
            catch
            {
                // swallow, log, whatever
            }
        }
    }
}
48
Marc Gravell

Cette fonction simple fonctionne bien et répond aux exigences des questions.

private List<string> GetFiles(string path, string pattern)
{
    var files = new List<string>();

    try 
    { 
        files.AddRange(Directory.GetFiles(path, pattern, SearchOption.TopDirectoryOnly));
        foreach (var directory in Directory.GetDirectories(path))
            files.AddRange(GetFiles(directory, pattern));
    } 
    catch (UnauthorizedAccessException) { }

    return files;
}
12
Ben Gripka

Pour ce faire, une méthode simple consiste à utiliser une liste pour les fichiers et une file d'attente pour les répertoires. Il conserve la mémoire. Si vous utilisez un programme récursif pour effectuer la même tâche, cela pourrait lever l'exception OutOfMemory. La sortie: les fichiers ajoutés dans la liste sont organisés selon l'arborescence de répertoires de haut en bas (largeur en premier).

public static List<string> GetAllFilesFromFolder(string root, bool searchSubfolders) {
    Queue<string> folders = new Queue<string>();
    List<string> files = new List<string>();
    folders.Enqueue(root);
    while (folders.Count != 0) {
        string currentFolder = folders.Dequeue();
        try {
            string[] filesInCurrent = System.IO.Directory.GetFiles(currentFolder, "*.*", System.IO.SearchOption.TopDirectoryOnly);
            files.AddRange(filesInCurrent);
        }
        catch {
            // Do Nothing
        }
        try {
            if (searchSubfolders) {
                string[] foldersInCurrent = System.IO.Directory.GetDirectories(currentFolder, "*.*", System.IO.SearchOption.TopDirectoryOnly);
                foreach (string _current in foldersInCurrent) {
                    folders.Enqueue(_current);
                }
            }
        }
        catch {
            // Do Nothing
        }
    }
    return files;
}

Pas:

  1. Mettre la racine dans la file d'attente
  2. En boucle, retirez-le de la file d'attente, ajoutez les fichiers de ce répertoire à la liste et ajoutez les sous-dossiers à la file d'attente.
  3. Répétez jusqu'à ce que la file d'attente soit vide.
5
Shubham

Je sais que cette question est un peu ancienne, mais j'ai eu ce même problème aujourd'hui et j'ai trouvé l'article suivant qui explique en détail une solution de "récursivité des dossiers".

L'article reconnaît les failles de la méthode GetDirectories() ...:

Malheureusement, cela [ en utilisant la méthode GetDirectories ()] a des problèmes. La clé parmi ceux-ci est que certains des dossiers que vous essayez de lire pourraient être configurés de sorte que l'utilisateur actuel ne puisse pas y accéder. Plutôt que d'ignorer les dossiers auxquels vous avez un accès restreint, la méthode lève une exception UnauthorizedAccessException. Cependant, nous pouvons contourner ce problème en créant notre propre code de recherche de dossier récursif.

... puis présente la solution en détail:

http://www.blackwasp.co.uk/FolderRecursion.aspx

3
sergeidave

Cela devrait répondre à la question. J'ai ignoré la question de passer par les sous-répertoires, je suppose que vous avez compris cela.

Bien sûr, vous n'avez pas besoin d'avoir une méthode distincte pour cela, mais vous pourriez y trouver un endroit utile pour vérifier également que le chemin est valide et gérer les autres exceptions que vous pourriez rencontrer lors de l'appel de GetFiles ().

J'espère que cela t'aides.

private string[] GetFiles(string path)
{
    string[] files = null;
    try
    {
       files = Directory.GetFiles(path);
    }
    catch (UnauthorizedAccessException)
    {
       // might be Nice to log this, or something ...
    }

    return files;
}

private void Processor(string path, bool recursive)
{
    // leaving the recursive directory navigation out.
    string[] files = this.GetFiles(path);
    if (null != files)
    {
        foreach (string file in files)
        {
           this.Process(file);
        }
    }
    else
    {
       // again, might want to do something when you can't access the path?
    }
}
2
user25306

voir https://stackoverflow.com/a/10728792/89584 pour une solution qui gère le problème UnauthorisedAccessException.

Toutes les solutions ci-dessus manqueront des fichiers et/ou des répertoires si des appels à GetFiles () ou GetDirectories () sont sur des dossiers avec un mélange d'autorisations.

1
Malcolm

Voici une implémentation complète et compatible .NET 2.0.

Vous pouvez même modifier le List des fichiers pour ignorer les répertoires dans la version FileSystemInfo!

(Méfiez-vous des valeurs null!)

public static IEnumerable<KeyValuePair<string, string[]>> GetFileSystemInfosRecursive(string dir, bool depth_first)
{
    foreach (var item in GetFileSystemObjectsRecursive(new DirectoryInfo(dir), depth_first))
    {
        string[] result;
        var children = item.Value;
        if (children != null)
        {
            result = new string[children.Count];
            for (int i = 0; i < result.Length; i++)
            { result[i] = children[i].Name; }
        }
        else { result = null; }
        string fullname;
        try { fullname = item.Key.FullName; }
        catch (IOException) { fullname = null; }
        catch (UnauthorizedAccessException) { fullname = null; }
        yield return new KeyValuePair<string, string[]>(fullname, result);
    }
}

public static IEnumerable<KeyValuePair<DirectoryInfo, List<FileSystemInfo>>> GetFileSystemInfosRecursive(DirectoryInfo dir, bool depth_first)
{
    var stack = depth_first ? new Stack<DirectoryInfo>() : null;
    var queue = depth_first ? null : new Queue<DirectoryInfo>();
    if (depth_first) { stack.Push(dir); }
    else { queue.Enqueue(dir); }
    for (var list = new List<FileSystemInfo>(); (depth_first ? stack.Count : queue.Count) > 0; list.Clear())
    {
        dir = depth_first ? stack.Pop() : queue.Dequeue();
        FileSystemInfo[] children;
        try { children = dir.GetFileSystemInfos(); }
        catch (UnauthorizedAccessException) { children = null; }
        catch (IOException) { children = null; }
        if (children != null) { list.AddRange(children); }
        yield return new KeyValuePair<DirectoryInfo, List<FileSystemInfo>>(dir, children != null ? list : null);
        if (depth_first) { list.Reverse(); }
        foreach (var child in list)
        {
            var asdir = child as DirectoryInfo;
            if (asdir != null)
            {
                if (depth_first) { stack.Push(asdir); }
                else { queue.Enqueue(asdir); }
            }
        }
    }
}
0
Mehrdad