GetFiles with multiple extensions

137,891

Solution 1

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");

Solution 2

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");

Solution 3

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();

Solution 4

You can use LINQ Union method:

dir.GetFiles("*.txt").Union(dir.GetFiles("*.jpg")).ToArray();

Solution 5

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.

Share:
137,891

Related videos on Youtube

rd42
Author by

rd42

Updated on August 06, 2020

Comments

  • rd42
    rd42 almost 4 years

    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");
    
    • Thomas Levesque
      Thomas Levesque over 13 years
      I guess you mean "more than one extension"... it doesn't work with two either
    • rd42
      rd42 over 13 years
      yeup doesn't work for two either
    • John Saunders
      John Saunders over 13 years
      BTW, are you aware that GetFiles is not related to C#, but only related to .NET?
    • Vikram
      Vikram almost 10 years
      @JohnSaunders, are you sure about this?
    • John Saunders
      John Saunders almost 10 years
      @VikramNarkar: yes. You won't find it in the C# Reference, and it works equally well from VB.NET or any other CLR language.
    • Vikram
      Vikram almost 10 years
      @JohnSaunders, Thanks a lot!
  • Thomas Levesque
    Thomas Levesque over 13 years
    That will be very inefficient if there are many files in the directory...
  • rd42
    rd42 over 13 years
    Thanks, I used the .NET 4 and got the following error. I'm new to this, so apologies is this is an obvious fix: Error 4 'bool' does not contain a definition for 'ToArray' and no extension method 'ToArray' accepting a first argument of type 'bool' could be found (are you missing a using directive or an assembly reference?)
  • Thomas Levesque
    Thomas Levesque over 13 years
    A closing bracket was missing, I fixed it
  • Thomas Levesque
    Thomas Levesque over 13 years
    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 ?
  • Cheng Chen
    Cheng Chen over 13 years
    Exactly.EnumerateFiles() is better at performance.
  • SLaks
    SLaks over 13 years
    This is inefficient.
  • SLaks
    SLaks over 13 years
    It would be faster to use a HashSet<string>.
  • Thomas Levesque
    Thomas Levesque over 13 years
    @SLaks, perhaps, depending on the number of extensions... For only 3 extensions I don't think the difference is significant.
  • Cheng Chen
    Cheng Chen over 13 years
    @Slaks: emm..it's better if I get all the files first and then filter it with different extensions.
  • SLaks
    SLaks over 13 years
    Yes. See my answer. Also, you ought to call SelectMany instead of Concat: return extensions.SelectMany(dir.GetFiles);
  • Jeff Winn
    Jeff Winn about 12 years
    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.
  • Doc Snuggles
    Doc Snuggles over 10 years
    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));
  • Wessam El Mahdy
    Wessam El Mahdy over 7 years
    Worked for me, thanks.
  • Jeff
    Jeff almost 7 years
    @DocSnuggles +1 per C# Interactive window> new[] { ".jpg", ".exe", ".gif" }.Contains(".GIF") false and > new[] { ".jpg", ".exe", ".gif" }.Contains(".GIF", StringComparer.OrdinalIgnoreCase) true
  • Developer63
    Developer63 over 5 years
    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.
  • Oleksii Zhyglov
    Oleksii Zhyglov over 5 years
    it is better to return array FilesInfo[], not collection, cause original method also returns n array:
  • Oleksii Zhyglov
    Oleksii Zhyglov over 5 years
    static class ExtensionMethods { public static 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)).ToArray(); } }
  • Dominic Isaia
    Dominic Isaia about 3 years
    I like this solution best because it's simple and easy to read.
  • Sid133
    Sid133 about 2 years
    For me, having a single .xlsx file in the dir folder, the result is coming up as 2 .xlsx file with same name
  • Ievgen
    Ievgen about 2 years
    @Sid133 how it can be? Union is performed on the different extensions.
  • Sid133
    Sid133 about 2 years
    @Ievgen No idea, i have posted problem statement here. stackoverflow.com/q/72041497/9304804