2009-10-10 4 views
4

En utilisant .NET 3.0, j'ai la méthode ci-dessous qui renvoie correctement une collection de tous les fichiers et répertoires (et sous-répertoires) d'un répertoire spécifié. Je voudrais, si possible, berner cela pour n'utiliser que des constructions avec lesquelles je suis plutôt à l'aise. Plus précisément, voici les choses que je ne suis pas clair sur:Méthode conviviale pour obtenir la liste de tous les fichiers et répertoires

1. IEnumerable<FileSystemInfo>: I'd like to return List<FileSystemInfo> instead 
2. Stack<FileSystemInfo>: I'd list to use List<FileSystemInfo> instead. 
3. yield return: I've never used this before 

.

public static IEnumerable<FileSystemInfo> GetAllFilesAndDirectories (string dir) { 

    DirectoryInfo dirInfo = new DirectoryInfo(dir); 
    Stack<FileSystemInfo> stack = new Stack<FileSystemInfo>(); 

    stack.Push(dirInfo); 
    while (dirInfo != null || stack.Count > 0) { 
     FileSystemInfo fileSystemInfo = stack.Pop(); 
     DirectoryInfo subDirectoryInfo = fileSystemInfo as DirectoryInfo; 
     if (subDirectoryInfo != null) { 
      yield return subDirectoryInfo; 
      foreach (FileSystemInfo fsi in subDirectoryInfo.GetFileSystemInfos()) { 
       stack.Push(fsi); 
      } 
      dirInfo = subDirectoryInfo; 
     } else { 
      yield return fileSystemInfo; 
      dirInfo = null; 
     } 
    } 

} 

.

L'argument pourrait être fait que je devrais juste me familiariser avec le code ci-dessus, mais ce n'est pas ce que je tire pour aujourd'hui.

Merci à l'avance

+0

Ajouté "Using .NET 3.0", à la question. –

Répondre

0

Je crois que vous cherchez les GetFileSystemInfos méthode existants (chaîne, SearchOptions). Si vous spécifiez AllDirectories comme valeur SearchOptions, il recherchera récursivement le dossier transmis.

Par exemple:

public static List<FileSystemInfo> GetAllFilesAndDirectories (string dir) { 
    DirectoryInfo info = new DirectoryInfo(dir); 
    FileSystemInfo[] all = info.GetFileSystemInfos("*", SearchOptions.AllDirectories); 
    return new List<FileSystemInfo>(all); 
} 

Si vous voulez écrire sur le long chemin que vous pouvez faire ce qui suit

public static List<FileSystemInfo> GetAllFilesAndDirectories (string dir) { 
    int i = 0; 
    List<DirectoryInfo> toProcess = new List<DirectoryInfo>(); 
    List<FileSystemInfo> list = new List<FileSystemInfo>(); 
    toProcess.Add(new DirectoryInfo(dir)); 
    while (i < toProcess.Count) { 
    DirectoryInfo curDir = toProcess[i]; 
    foreach (FileSystemInfo curFile in curDir.GetFileSystemInfos()) { 
     list.Add(curFile); 
     DirectoryInfo maybe = curFile as DirectoryInfo; 
     if (maybe != null) { 
     toProcess.Add(maybe); 
     } 
    i++; 
    } 
    return list; 
} 

    FileSystemInfo[] all = info.GetFileSystemInfos("*", SearchOptions.AllDirectories); 
    return new List<FileSystemInfo>(all); 
} 
+0

@bobbymcr, AllDirectories est une fonction de recherche récursive selon la documentation http://msdn.microsoft.com/en-us/library/ms143448(VS.100).aspx – JaredPar

+0

Cela ne fonctionne pas. L'OP veut apparemment obtenir tous les fichiers et répertoires dans tous les sous-dossiers, en commençant par le chemin donné. Cela retournera le premier niveau seulement. Notez qu'il n'y a pas de surcharge de GetFileSystemInfos qui peut accepter une énumération SearchOptions. – bobbymcr

+0

Oups, correction, il n'existe aucun moyen de le faire jusqu'à .NET 4.0. Donc, il sera éventuellement possible ... – bobbymcr

2

Voici le chemin le plus court, je peux penser à:

static List<FileSystemInfo> GetAllFilesAndDirectories(string dir) 
{ 
    DirectoryInfo dirInfo = new DirectoryInfo(dir);    
    List<FileSystemInfo> allFilesAndDirectories = new List<FileSystemInfo>(); 

    allFilesAndDirectories.AddRange(dirInfo.GetFiles("*", SearchOption.AllDirectories)); 
    allFilesAndDirectories.AddRange(dirInfo.GetDirectories("*", SearchOption.AllDirectories)); 

    return allFilesAndDirectories; 
} 

Il renverra une liste de tous les fichiers et répertoires à tous les niveaux, en commençant par le chemin donné. L'ordre dans lequel ils sont retournés serait tous les fichiers, puis tous les répertoires.

+0

+1: droit au but –

0

Vous aviez demandé spécifiquement de "stupide". Je pense que les deux autres réponses sont très bonnes, mais voici une autre façon de le faire avec encore plus de base, facilement compréhensible, au niveau du code de début.

http://support.microsoft.com/kb/303974

Modifier

Je sais que ce n'est pas 3.0, mais il est toujours le essayé, testé, et facile à comprendre de le faire.

1
public List<Object> GetFilesAndDirectories(string path) 
    { 
     List<Object> lst = new List<Object>(); 
     string[] dirs = null; 

     try 
     { 
      dirs = Directory.GetDirectories(path); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.Message); 
     } 

     foreach (string d in dirs) 
     { 
      string[] files = null; 

      try 
      { 
       files = Directory.GetFiles(d); 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.Message); 
      } 

      foreach (string f in files) 
      { 
       lst.Add(f); 
      } 

      lst.Add(d); 

      lst.AddRange(GetFilesAndDirectories(d)); 
     } 

     return lst; 
    } 


List<Object> stuff = GetFilesAndDirectories(someRoot); 
+2

Je tiens à souligner qu'il ne vaut pas mieux simplement «attraper» des exceptions, mieux vaut au moins les enregistrer. – RCIX

+0

Bien sûr. En outre, cela a été écrit avec un type d'objet générique pour la liste au cas où vous vouliez stocker des objets de fichiers/répertoires réels au lieu de représentations de chaînes. Personnalisez pour adapter à vos besoins. –

+0

Si vous voulez que votre instruction catch n'arrête pas littéralement la méthode, alors vous voudriez le bloc try/catch dans la boucle foreach. Ensuite, si vous attrapez une exception, vous continuerez à faire une boucle et regarder les autres fichiers dans le répertoire. –

0

Si vous voulez une "méthode débutant-friendly", je peux suggérer bobbymcr method.

Mais, si vous voulez garder la structure de votre code, je reproduis ci-dessous le code I posté dans your following question:

static IEnumerable<FileSystemInfo> GetAllFilesAndDirectories(string path) 
{ 
    string currentDirectory = ""; 
    string[] files = Directory.GetFiles(// skip empty subfolders 
     path, "*.*", SearchOption.AllDirectories); 
    foreach (string file in files) 
    { 
     if(currentDirectory != Path.GetDirectoryName(file)) 
     { 
      // First time in this directory: return it 
      currentDirectory = Path.GetDirectoryName(file); 
      yield return new DirectoryInfo(currentDirectory); 
     } 

     yield return new FileInfo(file); 
    } 
} 
0

Je pense que d'un point de vue de la lisibilité du code, votre meilleur pari est d'écrire une fonction récursive . Une fonction récursive est une fonction qui s'appelle elle-même, jusqu'à ce qu'elle atteigne un point où elle n'a plus besoin d'appeler une autre fonction. Pour illustrer, la factorielle de n, écrite comme n! et défini comme étant la quantité 1 x 2 x 3 x ... x n (où n est un entier positif) peut être assez facilement défini d'une manière récursive, comme suit.

public int factorial(int n) 
{ 
    if (n < 0) 
    { 
     throw new Exception("A factorial cannot be calculated for negative integers."); 
    } 

    if (n == 0 || n == 1) 
    { 
     // end condition, where we do not need to make a recursive call anymore 
     return 1; 
    } 
    else 
    { 
     // recursive call 
     return n * factorial(n - 1); 
    } 
} 

NB: 0! et 1! sont définis comme 1.

De même, une méthode permettant d'énumérer tous les fichiers et dossiers sous un chemin donné peut également être définie de manière récursive. C'est parce que les fichiers et les dossiers ont une structure récursive.

Par conséquent, un tel procédé comme suit, fonctionnerait:

public static List<FileSystemInfo> GetAllFilesAndFolders(string folder) 
{ 
    // NOTE : We are performing some basic sanity checking 
    // on the method's formal parameters here 
    if (string.IsNullOrEmpty(folder)) 
    { 
     throw new ArgumentException("An empty string is not a valid path.", "folder"); 
    } 
    if (!Directory.Exists(folder)) 
    { 
     throw new ArgumentException("The string must be an existing path.", "folder"); 
    } 

    List<FileSystemInfo> fileSystemInfos = new List<FileSystemInfo>(); 

    try 
    { 
     foreach (string filePath in Directory.GetFiles(folder, "*.*")) 
     { 
      // NOTE : We will add a FileSystemInfo object for each file found 
      fileSystemInfos.Add(new FileInfo(filePath)); 
     } 
    } 
    catch 
    { 
     // NOTE : We are swallowing all exceptions here 
     // Ideally they should be surfaced, and at least logged somewhere 
     // Most of these will be security/permissions related, i.e., 
     // the Directory.GetFiles method will throw an exception if it 
     // does not have security privileges to enumerate files in a folder. 
    } 
    try 
    { 
     foreach (string folderPath in Directory.GetDirectories(folder, "*")) 
     { 
      // NOTE : We will add a FileSystemInfo object for each directory found 
      fileSystemInfos.Add(new DirectoryInfo(folderPath)); 

      // NOTE : We will also add all FileSystemInfo objects found under 
      // each directory we find 
      fileSystemInfos.AddRange(GetAllFilesAndFolders(folderPath)); 
     } 
    } 
    catch 
    { 
     // NOTE : We are swallowing all exceptions here 
     // Ideally they should be surfaced, and at least logged somewhere 
     // Most of these will be security/permissions related, i.e., 
     // the Directory.GetDirectories method will throw an exception if it 
     // does not have security privileges to enumerate files in a folder. 
    } 

    return fileSystemInfos; 
} 

Une chose à noter est que cette méthode « marcher » la structure de répertoire entier sous le dossier et ne reviendra pas jusqu'à ce qu'il ait " marché "toute la hiérarchie. Par conséquent, il peut prendre beaucoup de temps à retourner, s'il y a beaucoup d'objets à trouver.

Une autre chose à noter est que la lisibilité de cette méthode peut être améliorée en utilisant des expressions Lambda et des méthodes d'extension. NB: Le problème avec l'utilisation de Directory.GetFiles et de Directory.GetDirectories pour recopier des sous-dossiers est que s'il y a des exceptions levées (par exemple, liées à des autorisations de sécurité), la méthode ne retournera rien, alors que récursive manuellement permet de gérer ces exceptions et toujours récupérer un ensemble de fichiers.

Questions connexes