This article shows how to retrieve subdirectories of a Windows directory iteratively instead of recursively. Typically, recursion is used to retrieve hierarchically recursive data such as directories. Please see my article Retrieving Hierarchically Recursive Data Iteratively for a description of retrieving hierarchically recursive data iteratively.
The example for this article is a console program that retrieves the directories of the user's Internet Explorer Favorites but could easily be adapted for other directories. If you are like me, your favorites are organized into many folders. This example does not retrieve the actual favorites, they are individual files within the directories. Reading the files (favorites) would be an easy addition.
To retrieve the directories, a class called "Folder" is used with the following members:
Name | Type | Description |
Name | string | Unqualified folder name |
Parent | Folder | Recursive reference to a parent folder |
Attributes | FileAttributes | |
CreationTime | DateTime | |
LastAccessTime | DateTime | |
LastWriteTime | DateTime | |
Children | List<Folder> | Subdirectories |
Level | int | Hierarchical depth, used only for formatting output |
GetFolder | Stack<Folder> ToDo, string root | Gets the subdirectories of the directory |
Qualify | string | Creates an absolute path |
Unqualify | string | Gets just the unqualified name of a directory |
PutFolder(Stack<Folder> ToDo, StreamWriter sw) | void | Writes the folder to the text file and queues the children |
Note that the Name is just the unqualified name and does not include the qualification.
The Internet Explorer Favorites are usually stored in the "C:\Users\{User}\Favorites" directory, so Name in the Folder object for the top folder to be processed is just "Favorites". We use the following to get the "C:\Users\{User}" portion:
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
To begin the iteration, we first create a "Folder" object for the top folder, "Favorites ", and push it onto the stack. After pushing "Favorites" onto the stack, we begin the iteration that pops it off the stack and processes it. We process each object (folder) by retrieving its children and pushing each of them onto the stack of folders to do.
The sample program retrieves the folders into "Folder" objects then uses (shows) a separate loop to write them to a text file. Note that you will need to change the name of the file in the sample program.
The following is the Main method of the console program:
- string RootFolderName = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
-
- Folder TopFolder = new Folder();
- TopFolder.Name = "Favorites";
- ToDo.Push(TopFolder);
- // Create a StreamWriter
- try {sw = new StreamWriter(OutFilename);}
- catch (Exception ex)
- {
- Console.WriteLine("Output file error: {0}", ex.Message);
- return;
- }
-
- Console.WriteLine("\tGetting");
- while (ToDo.Count > 0)
- {
- (ToDo.Pop()).GetFolder(ToDo, RootFolderName);
-
-
- Console.WriteLine("\tToDo.Count={0}", ToDo.Count);
- }
-
- Console.WriteLine("\tPutting");
- ToDo.Push(TopFolder);
- while (ToDo.Count > 0)
- {
- (ToDo.Pop()).PutFolder(ToDo, sw);
-
-
- Console.WriteLine("ToDo.Count={0}", ToDo.Count);
- }
- sw.Flush();
Where the "ToDo" stack is:
- static Stack<Folder> ToDo = new Stack<Folder>();
The following is the "GetFolder" method:
- internal void GetFolder(Stack<Folder> ToDo, string root)
- {
- string Path = root + '\\' + Qualify();
- DirectoryInfo di = new DirectoryInfo(Path);
- Attributes = di.Attributes;
- CreationTime = di.CreationTime;
- LastAccessTime = di.LastAccessTime;
- LastWriteTime = di.LastWriteTime;
- List<string> dirs = new List<string>(Directory.EnumerateDirectories(Path));
- foreach (string fn in dirs)
- {
- Folder sf = new Folder();
- sf.Name = Folder.Unqualify(fn);
- sf.Parent = this;
- sf.Level = Level + 1;
- Children.Add(sf);
- ToDo.Push(sf);
- }
- }
The following is the "PutFolder" method:
- internal void PutFolder(Stack<Folder> ToDo, StreamWriter sw)
- {
- string tabs = new string('\t', Level);
- sw.WriteLine("{0}{1} {2} {3}", tabs, Name, CreationTime, LastAccessTime);
-
-
-
- for (int i = Children.Count - 1; i >= 0; --i)
- ToDo.Push(Children[i]);
- }