The class offered below shows an implementation of an efficient way to scan large filesystem trees and returning the content. By not using recursion but controlling the worklist with a stack element a large part of the load on the GC is reduced. Using recursion the collection of created objects by the recusrive calls can’t be unwind until the entire process is completed, while by using a stack this control is left with the programmer. As a side result, the code becomes more linear which is usualy a good thing for readability.
The controlling application
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace TreeToy { class Program { static void Main(string[] args) { string dirtoscan = @"C:\users\bno"; string pattern = "*.png"; // Initiate a tree scanner and get the filesystem tree var scanner = new TreeScanner(dirtoscan, pattern); List<string> filelist = scanner.GetFileTree(); // Output results to console foreach (string s in filelist) { Console.WriteLine(s); } // End Console.Write("end-run"); Console.ReadLine(); } } }
The treescanner class
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace TreeToy { class TreeScanner { #region "Fields" private readonly string _basedirectory; // The directory to start scanning from private readonly string _pattern; // Optional, pattern *.jpg, etc #endregion #region "Constructors" /// <summary> /// Initiates a treescanner object from the given directory returning all files /// </summary> /// <param name="basedirectory"> public TreeScanner(string basedirectory) { _basedirectory = basedirectory; } /// <summary> /// Initiates a treescanner object from the given directory returning a specific pattern /// </summary> /// <param name="basedirectory">Directory to start scanning from /// <param name="pattern">Pattern (*.jpg, etc..) public TreeScanner(string basedirectory, string pattern) { _basedirectory = basedirectory; _pattern = pattern; } #endregion #region "Methods" /// <summary> /// Return all files in the filesystem tree starting at the base directory /// </summary> /// <returns></returns> public List<string> GetFileTree() { List<string> result = new List<string>(); var worklist = new Stack<string>(); worklist.Push(_basedirectory); while (worklist.Count > 0) { // Get a workitem string workfolder = worklist.Pop(); var dirinfo = new DirectoryInfo(workfolder); try { // Add all subfolders in the current workdirectory to the stack of items to be processed DirectoryInfo[] subfolders = dirinfo.GetDirectories(); foreach (DirectoryInfo subfolder in subfolders) { worklist.Push(subfolder.FullName); } // Add all files in the currect workdirectory to the result list FileInfo[] filelist = string.IsNullOrEmpty(_pattern) ? dirinfo.GetFiles() : dirinfo.GetFiles(_pattern); foreach (FileInfo fileInfo in filelist) { result.Add(fileInfo.FullName); } } catch (PathTooLongException) { // Long paths are possible, but a possible compat. nightmare, so we dont return long results. see: // http://msdn.microsoft.com/en-us/library/system.io.pathtoolongexception.aspx // http://blogs.msdn.com/b/bclteam/archive/2007/02/13/long-paths-in-net-part-1-of-3-kim-hamilton.aspx } } return result; } #endregion } }