Search code examples
c#recursion

Searching for file in directories recursively


I have the following code to recursively search for files through a directory, which returns a list of all xml files to me. All works well, except that xml files in the root directory are not included in the list.

I understand why, since the first thing it does is get the directories in the root, then get files, thus missing the GetFiles() call on the root. I tried including the GetFiles() call prior to the foreach, but the results are not as I expect.

public static ArrayList DirSearch(string sDir)
{
    try
    {
        foreach (string d in Directory.GetDirectories(sDir))
        {
            foreach (string f in Directory.GetFiles(d, "*.xml"))
            {
                string extension = Path.GetExtension(f);
                if (extension != null && (extension.Equals(".xml")))
                {
                fileList.Add(f);
                }
            }
            DirSearch(d);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
    return fileList;
}

My directory structure is something like:

RootDirectory
        test1.0.xml
            test1.1.xml
            test1.2.xml
  2ndLevDir
            test2.0.xml
            test2.1.xml
  3rdLevDir
               test3.0.xml
               test3.1.xml

Code returns:

test2.0.xml
test2.1.xml
test3.0.xml
test3.1.xml

I would like to return every file including:

test1.0.xml
test1.1.xml
test1.2.xml

Not very well verse with recursion. Any pointers would be greatly appreciated.


Solution

  • You could use this overload of Directory.GetFiles which searches subdirectories for you, for example:

    string[] files = Directory.GetFiles(sDir, "*.xml", SearchOption.AllDirectories);
    

    Only one extension can be searched for like that, but you could use something like:

    var extensions = new List<string> { ".txt", ".xml" };
    string[] files = Directory.GetFiles(sDir, "*.*", SearchOption.AllDirectories)
                        .Where(f => extensions.IndexOf(Path.GetExtension(f)) >= 0).ToArray();
    

    to select files with the required extensions (N.B. that is case-sensitive for the extension).

    If you want a case-insensitive extension check:

    var extensions = new List<string> { ".txt", ".xml" };
    var files = Directory.GetFiles(sDir, "*.*", SearchOption.AllDirectories)
                        .Where(f => extensions
                        .Any(extn => string.Compare(Path.GetExtension(f), extn, StringComparison.InvariantCultureIgnoreCase) == 0))
                        .ToArray();
    

    In some cases it can be desirable to enumerate over the files with the Directory.EnumerateFiles Method:

    foreach(string f in Directory.EnumerateFiles(sDir, "*.xml", SearchOption.AllDirectories))
    {
        // do something
    }
    

    Consult the documentation for exceptions which can be thrown, such as UnauthorizedAccessException if the code is running under an account which does not have appropriate access permissions.

    If the UnauthorizedAccessException is a problem, then please see the fine answers at Directory.EnumerateFiles => UnauthorizedAccessException.