C#
File Search
System.IO
Directory.GetFiles
Programming

Multiple file-extensions searchPattern for System.IO.Directory.GetFiles

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Directory.GetFiles accepts a single search pattern such as *.txt, but it does not support a compound pattern like *.txt|*.csv. When you need multiple extensions, the practical solution is to enumerate once and filter in code, or run multiple searches and combine the results.

What searchPattern Supports

The searchPattern argument supports wildcard matching, not a mini query language. These patterns work:

  • '*.txt'
  • 'report-*.csv'
  • 'file?.log'

This does not work:

csharp
Directory.GetFiles(path, "*.txt|*.csv");

The pipe character has no special meaning to GetFiles, so the method treats the string as a literal pattern and will not return the intended result.

A Good Modern Approach

If the directory may be large, use EnumerateFiles and filter by extension. This avoids allocating the full result set up front and keeps the logic readable.

csharp
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Linq;
5
6class Program
7{
8    static IEnumerable<string> FindFiles(string path, params string[] extensions)
9    {
10        var allowed = new HashSet<string>(
11            extensions.Select(ext => ext.StartsWith(".") ? ext : "." + ext),
12            StringComparer.OrdinalIgnoreCase);
13
14        return Directory.EnumerateFiles(path, "*", SearchOption.TopDirectoryOnly)
15            .Where(file => allowed.Contains(Path.GetExtension(file)));
16    }
17
18    static void Main()
19    {
20        foreach (string file in FindFiles(@"C:\Docs", ".txt", ".csv"))
21        {
22            Console.WriteLine(file);
23        }
24    }
25}

This approach is especially useful when you have many extensions or want case-insensitive matching.

Multiple Calls Can Still Be Fine

If the directory is small and the number of extensions is tiny, separate calls are straightforward:

csharp
1using System;
2using System.IO;
3using System.Linq;
4
5class Program
6{
7    static void Main()
8    {
9        string path = @"C:\Docs";
10
11        string[] files = Directory.GetFiles(path, "*.txt")
12            .Concat(Directory.GetFiles(path, "*.csv"))
13            .ToArray();
14
15        foreach (string file in files)
16        {
17            Console.WriteLine(file);
18        }
19    }
20}

The downside is that the directory gets scanned more than once. On local disks that may be acceptable. On network shares or deep recursive searches, it becomes less attractive.

Recursive Searches

The same filtering idea works with subdirectories too:

csharp
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Linq;
5
6class Program
7{
8    static IEnumerable<string> FindFilesRecursive(string path, params string[] extensions)
9    {
10        var allowed = new HashSet<string>(extensions, StringComparer.OrdinalIgnoreCase);
11
12        return Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)
13            .Where(file => allowed.Contains(Path.GetExtension(file)));
14    }
15
16    static void Main()
17    {
18        foreach (string file in FindFilesRecursive(@"C:\Projects", ".cs", ".xaml"))
19        {
20            Console.WriteLine(file);
21        }
22    }
23}

If you use SearchOption.AllDirectories, be ready for permission errors in protected folders. You may need custom traversal logic if you want to skip inaccessible directories instead of failing the whole search.

When a Helper Method Pays Off

If multi-extension lookup appears in more than one place, move it behind a helper method instead of repeating LINQ filters across the codebase. That keeps extension normalization, case-insensitive comparison, and traversal options consistent. It also makes later changes, such as excluding temporary folders or adding cancellation, much easier to apply in one place.

Why Not Use Regular Expressions First

You can apply a regular expression after enumeration, but it is usually unnecessary for simple extension checks. Path.GetExtension is clearer and cheaper. Reach for a regex only when the naming rule is more complex than extension matching.

Common Pitfalls

  • Trying to pass multiple patterns into GetFiles with separators like |, ;, or ,. The API does not parse them.
  • Using GetFiles for huge trees when EnumerateFiles would stream results more efficiently.
  • Forgetting case-insensitive matching on Windows if you compare extensions manually.
  • Assuming recursive search will quietly skip inaccessible directories. It can throw exceptions depending on the path and permissions.

Summary

  • 'Directory.GetFiles supports one wildcard pattern per call.'
  • For multiple extensions, enumerate once and filter with Path.GetExtension.
  • Separate GetFiles calls are acceptable for small, simple searches.
  • Prefer EnumerateFiles when performance or memory usage matters.
  • Be careful with recursive searches and permission-related exceptions.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.