2010-04-28 6 views
1

L'objectif final est d'avoir une forme de structure de données qui stocke une structure hiérarchique d'un répertoire à stocker dans un fichier txt. J'utilise le code suivant et jusqu'à présent, et j'ai du mal à combiner les répertoires, les sous-répertoires et les fichiers.Débutant - Itération C# dans le répertoire pour produire une liste de fichiers

/// <summary> 
/// code based on http://msdn.microsoft.com/en-us/library/bb513869.aspx 
/// </summary> 
/// <param name="strFolder"></param> 
public static void TraverseTree (string strFolder) 
{ 
    // Data structure to hold names of subfolders to be 
    // examined for files. 
    Stack<string> dirs = new Stack<string>(20); 

    if (!System.IO.Directory.Exists(strFolder)) 
    { 
    throw new ArgumentException(); 
    } 
    dirs.Push(strFolder); 

    while (dirs.Count > 0) 
    { 
    string currentDir = dirs.Pop(); 
    string[] subDirs; 
    try 
    { 
     subDirs = System.IO.Directory.GetDirectories(currentDir); 
    } 

    catch (UnauthorizedAccessException e) 
    { 
     MessageBox.Show("Error: " + e.Message); 
     continue; 
    } 
    catch (System.IO.DirectoryNotFoundException e) 
    { 
     MessageBox.Show("Error: " + e.Message); 
     continue; 
    } 

    string[] files = null; 
    try 
    { 
     files = System.IO.Directory.GetFiles(currentDir); 
    } 

    catch (UnauthorizedAccessException e) 
    { 
     MessageBox.Show("Error: " + e.Message); 
     continue; 
    } 

    catch (System.IO.DirectoryNotFoundException e) 
    { 
     MessageBox.Show("Error: " + e.Message); 
     continue; 
    } 
    // Perform the required action on each file here. 
    // Modify this block to perform your required task. 
    /* 
    foreach (string file in files) 
    { 
     try 
     { 
     // Perform whatever action is required in your scenario. 
     System.IO.FileInfo fi = new System.IO.FileInfo(file); 
     Console.WriteLine("{0}: {1}, {2}", fi.Name, fi.Length, fi.CreationTime); 
     } 
     catch (System.IO.FileNotFoundException e) 
     { 
     // If file was deleted by a separate application 
     // or thread since the call to TraverseTree() 
     // then just continue. 
     MessageBox.Show("Error: " + e.Message); 
     continue; 
     } 
    } 
    */ 

    // Push the subdirectories onto the stack for traversal. 
    // This could also be done before handing the files. 
    foreach (string str in subDirs) 
     dirs.Push(str); 

    foreach (string str in files) 
     MessageBox.Show(str); 
    } 
+0

Je pense que vous Je vais devoir exposer votre problème plus clairement. Le code semble bien au premier coup d'œil. – dtb

+0

BTW l'algorithme fonctionne itérativement avec une pile explicite, pas récursivement. – dtb

+1

N'ayez pas peur de la récursivité! –

Répondre

0

Je l'ai travail en utilisant le code basé sur http://weblogs.asp.net/israelio/archive/2004/06/23/162913.aspx

// How much deep to scan. (of course you can also pass it to the method) 
const int HowDeepToScan=20; 

public static void ProcessDir (string dirName, int recursionLvl, string strFileName) 
{ 

    string tabs = new String('-', recursionLvl); 

    if (recursionLvl<=HowDeepToScan) 
    { 
    // Process the list of files found in the directory. 
    string [] fileEntries = Directory.GetFiles(dirName); 
    TextWriter tw = new StreamWriter(strFileName, true); 
    tw.WriteLine(tabs + "<a href=\" " + System.IO.Path.GetFullPath(dirName) + "\">" + System.IO.Path.GetFileName(dirName) + "</a><br />"); 
    foreach (string fileName in fileEntries) 
    { 
     // do something with fileName 

     tw.WriteLine(tabs + "<a href=\" " + System.IO.Path.GetFullPath(fileName) + "\">" + System.IO.Path.GetFileName(fileName) + "</a><br />"); 

    } 
    tw.Close(); 

    // Recurse into subdirectories of this directory. 
    string [] subdirEntries = Directory.GetDirectories(dirName); 
    foreach (string subdir in subdirEntries) 
     // Do not iterate through reparse points 
     if ((File.GetAttributes(subdir) & 
     FileAttributes.ReparsePoint) != 
      FileAttributes.ReparsePoint) 

     ProcessDir(subdir, recursionLvl+1, strFileName); 

    } 
} 

sortie

<a href=" C:\code">code</a><br /> 
<a href=" C:\code\group.zip">FluentPath (1).zip</a><br /> 
<a href=" C:\code\index.html">index.html</a><br /> 
8

Vous pouvez utiliser une sorte de Composite pattern où un élément composite - est un dossier.

Voici un exemple de code qui construit la structure arborescente du dossier cible. Cela fonctionne récursivement, et consomme un peu plus de mémoire, mais la simplicité en vaut la peine.

class TreeItem 
{ 
    public string FolderName; 
    public List<TreeItem> SubFolders = new List<TreeItem>(); 
    public string[] Files; 
} 

class Program 
{ 

    private static TreeItem FileTree(string rootFolder){ 
     var item = new TreeItem(); 
     item.FolderName = rootFolder; 
     item.Files = System.IO.Directory.GetFiles(rootFolder); 

     foreach(var folder in System.IO.Directory.GetDirectories(rootFolder)) 
     { 
      item.SubFolders.Add(FileTree(folder)); 
     } 
     return item; 
    } 

    //Traversal algorithm 
    private static void PrintComposite(TreeItem node, int ident) 
    { 
     var dirName = System.IO.Path.GetFileName(node.FolderName); 
     Console.WriteLine(@"{0}{1}", new string('-', ident), dirName); 
     foreach(var subNode in node.SubFolders) 
     { 
      PrintComposite(subNode, ident + 1); 
     } 
    } 

    public static void Main(string[] args) 
    { 
     var tree = FileTree(@"D:\Games"); 
     PrintComposite(tree,0); 
    } 
} 
+0

Cela fonctionne très bien; cependant, je veux également ajouter des fichiers à la liste, j'ai joué avec printnode et en ajoutant un autre foreach, je vais voir si je peux le faire fonctionner .. jusqu'à présent c'est super – dassouki

1

D'une part, je pense que vous devez créer plus d'objets. Une interface DirectoryElementInterface ou une classe abstraite et un objet DirectoryElement et un objet FileElement qui implémentent DirectoryElementInterface. Maintenant, plutôt que d'utiliser une pile pour parcourir la hiérarchie, créez DirectoryElementInterface root = new DirectoryElement(nameOfNode). Ensuite, pour chaque fichier dans getFiles faire quelque chose comme root.addElement(new FileElement(filename));. addElement doit être ajouté à une liste dans DirectoryElement. Faites de même pour les répertoires. OK, maintenant vous pouvez créer un niveau.

Maintenant pour l'étape d'itération. Prenez la routine que vous venez d'écrire et faites root un paramètre. Vous pouvez l'appeler n'importe quoi mais pour cette discussion, je vais appeler cette nouvelle routine addDirectoryInformation. Votre principal sera maintenant la création de la racine et l'appel addDirectoryInformation passant à la racine. Pour itérer, nous devons demander la racine maintenant remplie pour sa liste d'éléments, faire un foreach sur la liste et appeler addDirectoryInformation pour chacun des éléments qui est un répertoire. Une fois que vous avez ce travail, déplacez la boucle dans la fin de addDirectoryInformation. Maintenant, chaque répertoire ajouté ajoute tous ses enfants de manière récursive.

Encore une chose pour un programme récursif approprié. Vous devez savoir quand arrêter de récurer. Dans ce cas, c'est facile. S'il n'y a aucun répertoire dans la liste, addDirectoryInformation n'est jamais appelé. Donc vous avez terminé.

+0

La tâche initiale est un peu floue, une telle complexité ne serait-elle pas excessive? Le motif composite est conçu pour aider à uniformiser le traitement de chaque nœud et de chaque feuille de façon cohérente, mais maintenant, il n'est pas requis. –

0

Je l'ai fait un cours la semaine dernière où nous avons fait quelque chose de similaire, la sortie était à la console, mais aucune raison vous ne pouvez pas le streamwrite dans un fichier .txt.

en utilisant System; en utilisant System.Collections.Generic; en utilisant System.Linq; en utilisant System.Text;

espace de noms ShowDirectory { class Program { static void Main (string [] args) { Console.WriteLine ("Ce programme répertorie tous les fichiers dans le répertoire."); System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo (@ "C: \"); foreach (fichier System.IO.FileInfo dans dir.GetFiles ("")) { Console.WriteLine ("{0}, {1}", fichier.Nom, fichier.Longueur); } Console.ReadLine(); } } }

0

L'une des approches consiste à utiliser itérateur sur l'arbre de fichiers comme ceci:

// IncludeExcludeFileEnumerator(string baseDir, string includePattern, string excludePattern) 
// Include pattern can include ** that means tree hierarchy 
var myFiles = new IncludeExcludeFileEnumerable(@"C:\test\aaa", @"**.bmp,*.jpg", "*excl_bad*.*,*fu*"); 
foreach (var s in myFiles) 
{ 
    Console.Out.WriteLine(s); 
} 
code

pour le fichier iterator (IEnumerator, IEnumerable):

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Text.RegularExpressions; 

namespace IncludeExcludeFileEnumerator 
{ 
    public class IncludeExcludeFileEnumerator : IEnumerator<String> 
    { 
     private string excludeRegExPattern; 
     private readonly Regex regexSeparateFilePath; 
     private readonly Regex excludeRegex = null; 
     private int currentPatternIndex; 
     private IEnumerator<string> filesEnum; 
     private IEnumerable<string> files; 
     bool isNext = true; 
     private readonly List<Tuple<string, string, SearchOption>> incPatternsList; 


     public IncludeExcludeFileEnumerator(string baseDirectory, string includePattern, string excludePattern) 
     { 
      // Split comma separated string to array of include patterns 
      var initIncludePatterns = includePattern.Split(','); 
      regexSeparateFilePath = new Regex(@"(.*)[\\/]([^\\/]*$)", RegexOptions.Compiled); 

      // Prepare include patterns 
      incPatternsList = initIncludePatterns.ToList().ConvertAll(
       (incPattern) => 
       { 
        incPattern = incPattern.Trim(); 
        var matches = regexSeparateFilePath.Matches(incPattern); 
        string pathPattern; 
        string filePattern; 
        if (matches.Count == 0) 
        { 
         pathPattern = ""; 
         filePattern = incPattern; 
        } 
        else 
        { 
         pathPattern = matches[0].Groups[1].Value; 
         filePattern = matches[0].Groups[2].Value; 
        } 
        SearchOption searchOption = SearchOption.TopDirectoryOnly; 
        if (filePattern.Contains("**")) 
        { 
         filePattern = filePattern.Replace("**", "*"); 
         searchOption = SearchOption.AllDirectories; 
        } 
        var fullPathPattern = Path.Combine(baseDirectory, pathPattern); 
        // Returns tuple {PathPattern, FilePattern, SearchOption} 
        return new Tuple<string, string, SearchOption>(fullPathPattern, filePattern, searchOption); 
       }); 

      // Prepare regular expression for exclude case (all in one, concatinated by (| - or) separator) 
      if (!String.IsNullOrWhiteSpace(excludePattern)) 
      { 
       var excPatterns = excludePattern.Replace(".", @"\."); 
       excPatterns = excPatterns.Replace("*", ".*"); 
       excludeRegExPattern = excPatterns.Replace(",", "|"); 
       excludeRegex = new Regex(excludeRegExPattern, RegexOptions.Compiled); 
      } 
      Reset(); 
     } 

     public string Current 
     { 
      get { return filesEnum.Current; } 
     } 

     public void Dispose() 
     { 

     } 

     object System.Collections.IEnumerator.Current 
     { 
      get { return (Object)this.Current; } 
     } 

     public bool MoveNext() 
     { 
      do 
      { 
       if ((filesEnum == null) && (incPatternsList.Count < currentPatternIndex + 2)) 
       { 
        return false; 
       } 
       if ((filesEnum == null) || (isNext == false)) 
       { 
        var tuple = incPatternsList[++currentPatternIndex]; 
        files = Directory.EnumerateFiles(tuple.Item1, tuple.Item2, tuple.Item3); 
        filesEnum = files.GetEnumerator(); 
        isNext = true; 
       } 
       while (isNext) 
       { 
        isNext = filesEnum.MoveNext(); 
        if (isNext) 
        { 
         if (excludeRegex==null) return true; 
         if (!excludeRegex.Match(filesEnum.Current).Success) return true; 
         // else continue; 
        } 
        else 
        { 
         filesEnum = null; 
        } 
       } 
      } while (true); 
     } 

     public void Reset() 
     { 
      currentPatternIndex = -1; 
      filesEnum = null; 
     } 
    } 

    public class IncludeExcludeFileEnumerable : IEnumerable<string> 
    { 
     private string baseDirectory; 
     private string includePattern; 
     private string excludePattern; 

     public IncludeExcludeFileEnumerable(string baseDirectory, string includePattern, string excludePattern) 
     { 
      this.baseDirectory = baseDirectory; 
      this.includePattern = includePattern; 
      this.excludePattern = excludePattern; 
     } 

     public IEnumerator<string> GetEnumerator() 
     { 
      return new IncludeExcludeFileEnumerator(baseDirectory, includePattern, excludePattern); 
     } 

     System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
     { 
      return (IEnumerator)this.GetEnumerator(); 
     } 
    } 
}