104

Possible Duplicate:
Can you call Directory.GetFiles() with multiple filters?

How do you filter on more than one extension?

I've tried:

FileInfo[] Files = dinfo.GetFiles("*.jpg;*.tiff;*.bmp");
FileInfo[] Files = dinfo.GetFiles("*.jpg,*.tiff,*.bmp");
Cœur
  • 37,241
  • 25
  • 195
  • 267
rd42
  • 3,584
  • 15
  • 56
  • 68

7 Answers7

78

Why not create an extension method? That's more readable.

public static IEnumerable<FileInfo> GetFilesByExtensions(this DirectoryInfo dir, params string[] extensions)
{
    if (extensions == null) 
         throw new ArgumentNullException("extensions");
    IEnumerable<FileInfo> files = Enumerable.Empty<FileInfo>();
    foreach(string ext in extensions)
    {
       files = files.Concat(dir.GetFiles(ext));
    }
    return files;
}

EDIT: a more efficient version:

public static IEnumerable<FileInfo> GetFilesByExtensions(this DirectoryInfo dir, params string[] extensions)
{
    if (extensions == null) 
         throw new ArgumentNullException("extensions");
    IEnumerable<FileInfo> files = dir.EnumerateFiles();
    return files.Where(f => extensions.Contains(f.Extension));
}

Usage:

DirectoryInfo dInfo = new DirectoryInfo(@"c:\MyDir");
dInfo.GetFilesByExtensions(".jpg",".exe",".gif");
Demodave
  • 6,242
  • 6
  • 43
  • 58
Cheng Chen
  • 42,509
  • 16
  • 113
  • 174
  • 7
    This is inefficient. – SLaks Nov 08 '10 at 13:44
  • @Slaks: emm..it's better if I get all the files first and then filter it with different extensions. – Cheng Chen Nov 08 '10 at 14:59
  • 2
    Yes. See my answer. Also, you ought to call `SelectMany` instead of `Concat`: `return extensions.SelectMany(dir.GetFiles);` – SLaks Nov 08 '10 at 15:33
  • 1
    Rather than checking the extension as shown above, you can use the first example and pass the search pattern into EnumerateFiles and still be able to use checks against the filename rather than only being able to inspect the extension while retaining the efficiency of the 2nd example. – Jeff Winn Mar 08 '12 at 16:42
  • 4
    To avoid missing Capital Written Extensions I would add a StringComparer.OrdinalIgnoreCase to the Contains-Method. `return files.Where(f => extensions.Contains(f.Extension, StringComparer.OrdinalIgnoreCase));` – Doc Snuggles Nov 12 '13 at 11:14
  • @DocSnuggles +1 per C# Interactive window`> new[] { ".jpg", ".exe", ".gif" }.Contains(".GIF") false` and `> new[] { ".jpg", ".exe", ".gif" }.Contains(".GIF", StringComparer.OrdinalIgnoreCase) true` – Jeff Aug 10 '17 at 19:59
  • it is better to return array FilesInfo[], not collection, cause original method also returns n array: – Oleksii Zhyglov Jan 14 '19 at 09:59
  • 1
    static class ExtensionMethods { public static FileInfo[] GetFilesByExtensions(this DirectoryInfo dir, params string[] extensions) { if (extensions == null) throw new ArgumentNullException("extensions"); IEnumerable files = dir.EnumerateFiles(); return files.Where(f => extensions.Contains(f.Extension)).ToArray(); } } – Oleksii Zhyglov Jan 14 '19 at 09:59
73

You can get every file, then filter the array:

public static IEnumerable<FileInfo> GetFilesByExtensions(this DirectoryInfo dirInfo, params string[] extensions)
{
    var allowedExtensions = new HashSet<string>(extensions, StringComparer.OrdinalIgnoreCase);

    return dirInfo.EnumerateFiles()
                  .Where(f => allowedExtensions.Contains(f.Extension));
}

This will be (marginally) faster than every other answer here.
In .Net 3.5, replace EnumerateFiles with GetFiles (which is slower).

And use it like this:

var files = new DirectoryInfo(...).GetFilesByExtensions(".jpg", ".mov", ".gif", ".mp4");
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • This does not find sub folders. I modified the code like this do you think correct? return dirInfo.EnumerateFiles("*.*",enumerationOptions: new EnumerationOptions { RecurseSubdirectories=true}) .Where(f => allowedExtensions.Contains(f.Extension)); – Furkan Gözükara Dec 27 '22 at 08:48
60

You can't do that, because GetFiles only accepts a single search pattern. Instead, you can call GetFiles with no pattern, and filter the results in code:

string[] extensions = new[] { ".jpg", ".tiff", ".bmp" };

FileInfo[] files =
    dinfo.GetFiles()
         .Where(f => extensions.Contains(f.Extension.ToLower()))
         .ToArray();

If you're working with .NET 4, you can use the EnumerateFiles method to avoid loading all FileInfo objects in memory at once:

string[] extensions = new[] { ".jpg", ".tiff", ".bmp" };

FileInfo[] files =
    dinfo.EnumerateFiles()
         .Where(f => extensions.Contains(f.Extension.ToLower()))
         .ToArray();
Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
27

You can use LINQ Union method:

dir.GetFiles("*.txt").Union(dir.GetFiles("*.jpg")).ToArray();
Ievgen
  • 4,261
  • 7
  • 75
  • 124
  • 1
    Fantastic solution, worked perfectly for me. I like that it's one line of code, the line is very readable and clear in its intent, I know what it's doing and why at a glance. – Developer63 Nov 28 '18 at 01:06
  • For me, having a single .xlsx file in the dir folder, the result is coming up as 2 .xlsx file with same name – Sid133 Apr 28 '22 at 09:55
  • @Sid133 how it can be? Union is performed on the different extensions. – Ievgen Apr 28 '22 at 11:37
  • @Ievgen No idea, i have posted problem statement here. https://stackoverflow.com/q/72041497/9304804 – Sid133 Apr 28 '22 at 12:44
9

The following retrieves the jpg, tiff and bmp files and gives you an IEnumerable<FileInfo> over which you can iterate:

var files = dinfo.GetFiles("*.jpg")
    .Concat(dinfo.GetFiles("*.tiff"))
    .Concat(dinfo.GetFiles("*.bmp"));

If you really need an array, simply stick .ToArray() at the end of this.

Timwi
  • 65,159
  • 33
  • 165
  • 230
3

I'm not sure if that is possible. The MSDN GetFiles reference says a search pattern, not a list of search patterns.

I might be inclined to fetch each list separately and "foreach" them into a final list.

ddm
  • 478
  • 5
  • 14
0

I know there is a more elegant way to do this and I'm open to suggestions... this is what I did:

          try
            {


             // Set directory for list to be made of
                DirectoryInfo jpegInfo = new DirectoryInfo(destinationFolder);
                DirectoryInfo jpgInfo = new DirectoryInfo(destinationFolder);
                DirectoryInfo gifInfo = new DirectoryInfo(destinationFolder);
                DirectoryInfo tiffInfo = new DirectoryInfo(destinationFolder);
                DirectoryInfo bmpInfo = new DirectoryInfo(destinationFolder);

                // Set file type
                FileInfo[] Jpegs = jpegInfo.GetFiles("*.jpeg");
                FileInfo[] Jpgs = jpegInfo.GetFiles("*.jpg");
                FileInfo[] Gifs = gifInfo.GetFiles("*.gif");
                FileInfo[] Tiffs = gifInfo.GetFiles("*.tiff");
                FileInfo[] Bmps = gifInfo.GetFiles("*.bmp");

        //  listBox1.Items.Add(@"");  // Hack for the first list item no preview problem
        // Iterate through each file, displaying only the name inside the listbox...
        foreach (FileInfo file in Jpegs)
        {
                listBox1.Items.Add(file.Name);
                Photo curPhoto = new Photo();
                curPhoto.PhotoLocation = file.FullName;
                metaData.AddPhoto(curPhoto);
            }

          foreach (FileInfo file in Jpgs)
          {
              listBox1.Items.Add(file.Name);
                Photo curPhoto = new Photo();
                curPhoto.PhotoLocation = file.FullName;
                metaData.AddPhoto(curPhoto);
            }
          foreach (FileInfo file in Gifs)
          {
              listBox1.Items.Add(file.Name);
              Photo curPhoto = new Photo();
              curPhoto.PhotoLocation = file.FullName;
              metaData.AddPhoto(curPhoto);
          }
          foreach (FileInfo file in Tiffs)
          {
              listBox1.Items.Add(file.Name);
              Photo curPhoto = new Photo();
              curPhoto.PhotoLocation = file.FullName;
              metaData.AddPhoto(curPhoto);
          }
          foreach (FileInfo file in Bmps)
          {
              listBox1.Items.Add(file.Name);
              Photo curPhoto = new Photo();
              curPhoto.PhotoLocation = file.FullName;
              metaData.AddPhoto(curPhoto);
          }
rd42
  • 3,584
  • 15
  • 56
  • 68
  • You don't need to create a separate instance of DirectoryInfo for each type... and there is a lot of repeated code, you should refactor that with a method. Anyway, I updated my answer to fix the error, did you try it ? – Thomas Levesque Aug 20 '10 at 01:42