Finding files: Recursion vs Stack<>…FIGHT!
I was just poking around the Internet and came across a blog post highlighting a solution to a common problem: find all files matching a criteria (e.g. *.dll) from a folder and all its subfolders (e.g. c:\windows and all subdirectories). In this post, I compare the speed of two methods using code in C#.
Method 1 involves recursion. I saw a sample at http://www.gfilter.net/default.aspx?Post=Code-Snippet-of-the-Day%3a-Recursive-File-Finder and MSDN.
Method 2 involves using a stack to process subdirectories in a Last in, first out manner. I saw this from http://dotnetperls.com/Content/Recursively-Find-Files.aspx.
The result from finding all 13,300+ DLLs in c:\windows and all subdirectories:
FileFinderRecursive Elapsed: 6876ms.
FileFinderStack Elapsed: 5725ms.
The stack method was almost 20% faster.
Here’s some code from a quick C# console app I just wrote to compare the two:
class Program
{
static void Main(string[] args)
{
Stopwatch s;
IFinder finder;
string startDir = @"c:\windows";
string matchType = "*.dll";
//Test Recursion method
s = Stopwatch.StartNew();
finder = new FileFinderRecursive();
var filesRecursive = finder.Find(startDir, matchType);
s.Stop();
Console.WriteLine("FileFinderRecursive Elapsed: " + s.ElapsedMilliseconds + "ms.");
//Test Stack method
s = Stopwatch.StartNew();
finder = new FileFinderStack();
var filesStack = finder.Find(startDir, matchType);
s.Stop();
Console.WriteLine("FileFinderStack Elapsed: " + s.ElapsedMilliseconds + "ms.");
Console.Read();
}
}
public interface IFinder
{
List<FileInfo> Find(string startDir, string matchType);
}
/// <summary>
/// Recursively finds a list of files that match the specified critiria
/// </summary>
public class FileFinderRecursive : IFinder
{
private Dictionary<FileInfo, int> files;
public List<FileInfo> Find(string startDir, string matchType)
{
files = new Dictionary<FileInfo, int>();
findFiles(startDir, matchType);
return files.Keys.ToList();
}
private void findFiles(string startDir, string matchType)
{
DirectoryInfo d = new DirectoryInfo(startDir);
FileInfo[] fileInfos;
try
{
fileInfos = d.GetFiles(matchType);
}
catch
{
return; //most likely Access Exception. BAIL!
}
foreach (FileInfo f in fileInfos)
{
if (!files.ContainsKey(f))
{
files.Add(f, 0);
}
}
if (d.GetDirectories().Length > 0)
{
foreach (DirectoryInfo subD in d.GetDirectories())
{
findFiles(subD.FullName, matchType);
}
}
}
}
/// <summary>
/// Finds a list of files that match the specified criteria using a stack
/// </summary>
public class FileFinderStack : IFinder
{
public List<FileInfo> Find(string startDir, string matchType)
{
DirectoryInfo dirStart = new DirectoryInfo(startDir);
List<FileInfo> result = new List<FileInfo>();
Stack<DirectoryInfo> stack = new Stack<DirectoryInfo>();
stack.Push(dirStart);
while (stack.Count > 0)
{
DirectoryInfo dir = stack.Pop();
try
{
result.AddRange(dir.GetFiles(matchType));
DirectoryInfo[] subDirs = dir.GetDirectories();
foreach (DirectoryInfo dn in subDirs)
{
stack.Push(dn);
}
}
catch { }
}
return result;
}
}
afdsa