C# & ADO.NET

List all files in a folder and its subfolders in C#

C# & ADO.NET · · Published 2026-09-14

.NET can list every file below a folder in one call. The choices are between getting an array at once (GetFiles) or streaming results (EnumerateFiles), and deciding what to do with folders you are not allowed to read.

One line

using System.IO;

string[] all = Directory.GetFiles(@"C:\Data\Reports", "*.*", SearchOption.AllDirectories);
string[] pdfs = Directory.GetFiles(@"C:\Data\Reports", "*.pdf", SearchOption.AllDirectories);

GetFiles builds the whole array before returning. EnumerateFiles returns results as it finds them, so you can start processing immediately and stop early:

foreach (string path in Directory.EnumerateFiles(root, "*.log", SearchOption.AllDirectories))
{
    if (new FileInfo(path).Length > 100_000_000) { Console.WriteLine("Large: " + path); }
}

Access denied in one subfolder

With SearchOption.AllDirectories on .NET Framework, a single unreadable subfolder throws UnauthorizedAccessException and you lose the whole result. Walk the tree yourself and skip what you cannot read:

public static IEnumerable<string> SafeEnumerateFiles(string root, string pattern)
{
    var pending = new Stack<string>();
    pending.Push(root);
    while (pending.Count > 0)
    {
        string dir = pending.Pop();
        string[] files = Array.Empty<string>(), subdirs = Array.Empty<string>();
        try
        {
            files = Directory.GetFiles(dir, pattern);
            subdirs = Directory.GetDirectories(dir);
        }
        catch (UnauthorizedAccessException) { }
        catch (DirectoryNotFoundException) { }

        foreach (string f in files) yield return f;
        foreach (string d in subdirs) pending.Push(d);
    }
}

On .NET Core 2.1 and later (including .NET 8), EnumerationOptions does this for you: new EnumerationOptions { RecurseSubdirectories = true, IgnoreInaccessible = true }.

Pattern quirks

Showing the files on a Web Forms page

string root = Server.MapPath("~/App_Data/reports");
var rows = SafeEnumerateFiles(root, "*")
    .Select(p => new FileInfo(p))
    .Select(f => new
    {
        Folder = f.DirectoryName.Substring(root.Length).TrimStart('\\'),
        f.Name,
        SizeKb = Math.Ceiling(f.Length / 1024.0),
        Modified = f.LastWriteTime
    })
    .OrderBy(x => x.Folder).ThenBy(x => x.Name)
    .ToList();
gvFiles.DataSource = rows;
gvFiles.DataBind();

Only list folders the application owns, never a path taken from user input; and the application pool identity needs read permission on them. Exporting such a list to CSV or Excel: Export a folder's file list.

Performance notes

Enumerating a large network share can take minutes. Avoid doing it inside a web request: run it in a scheduled job, store the result (for example in a table), and let the page read that. When you must enumerate on demand, use EnumerateFiles, stop as soon as you have what you need, and avoid calling new FileInfo(path) for every file unless you need sizes or dates; DirectoryInfo.EnumerateFiles returns FileInfo objects whose basic properties come from the directory listing itself.

Official documentation