Recently I need to write some code to read all files in a directory and it’s sub-directories. There are simple way and difficult way (Not very difficult actually). The simple way will be writing a function that reads all files in the directory and call the function again recursively for each sub-directory in that directory.
Although it is simple but it is not efficient, especially when running on a small computer (e.g. handheld device), it can use up a lot of call stack space when the recursion is too deep. Besides it is very hard to debug or extend the functionality in case of recursive logic.
Here is the recursion version of looping all files in the directory and it’s sub-directories:
void ProcessFiles(string path)
{
string[] files;
string[] directories;
files = Directory.GetFiles(path);
foreach(string file in files)
{
// Process each file
}
directories = Directory.GetDirectories(path);
foreach(string directory in directories)
{
// Process each directory recursively
ProcessFiles(directory);
}
}
Instead of using the recursion way of looping all the files in directory and it’s sub-directories, we can change it to iteration way by introduce a stack instance. The iteration way of doing this task is much more efficient. The iteration way will be writing a function that loop all the directory stored in the stack instance. In each loop, files are processed and when more directories are discovered, simply push the directory into the stack instance.
Here is the ieteration version of looping all files in the directory and it’s sub-directories:
void ProcessFiles(string path)
{
Stack<string> stack;
string[] files;
string[] directories;
string dir;
stack = new Stack();
stack.Push(path);
while (stack.Count > 0) {
// Pop a directory
dir = stack.Pop();
files = Directory.GetFiles(dir);
foreach(string file in files)
{
// Process each file
}
directories = Directory.GetDirectories(dir);
foreach(string directory in directories)
{
// Push each directory into stack
stack.Push(directory);
}
}
}
Note: The codes above do not catch any exception. It is always good practice to catch and handle all possible exceptions throwing from functions (e.g. Permission exception of reading files and e.t.c.)
marco says
good evening,
you have two errors in the code
faux : dir = stack.Pop();
Vrai : dir = (string)stack.pop();
And
faux : directories = Directory.GetDirectories(path);
vrai : directories = Directory.GetDirectories(dir);
thank you very much for this code
marc
szehau says
For the first statement, my original code should declare stack as a string stack
Stack<string>
. I have fixed that now.For the second statement, you are right. I have fixed that too. My mistake 🙂
Thanks.
Scott Leckie says
I like (and use) this technique. The only things I would add are that, in a real world environment there are a couple of pseudo-expected exceptions that you may hit; UnauthorizedAccessException and PathTooLongException). My sample code pretty much mimics yours but also takes into account these “acceptable exceptions”. Please have a look at http://www.scottleckie.com/2009/07/iterating-through-a-bunch-of-folders-and-files/
Cheers
Scott
szehau says
Yes, my sample doesn’t handle any “acceptable exception” because I think it depends on what you application need. Some may just simply want to skip the file for certain exceptions and some may want to stop the application for all exceptions.
Scott Leckie says
Indeed. It wasn’t a criticism, just a fact of life if the app will be used by lots of different users to look at a remote file system, and they don’t necessarily have rights to the entire structure.
Regards
Scott