GetFiles with multiple extensions [duplicate]
Asked Answered
S

7

105

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");
Sweaty answered 19/8, 2010 at 23:55 Comment(5)
I guess you mean "more than one extension"... it doesn't work with two eitherLapse
yeup doesn't work for two eitherSweaty
BTW, are you aware that GetFiles is not related to C#, but only related to .NET?Gibbsite
@JohnSaunders, are you sure about this?Pickel
@VikramNarkar: yes. You won't find it in the C# Reference, and it works equally well from VB.NET or any other CLR language.Gibbsite
R
80

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");
Rhinehart answered 20/8, 2010 at 2:15 Comment(8)
This is inefficient.Studnia
@Slaks: emm..it's better if I get all the files first and then filter it with different extensions.Rhinehart
Yes. See my answer. Also, you ought to call SelectMany instead of Concat: return extensions.SelectMany(dir.GetFiles);Studnia
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.Hurter
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));Borchardt
@DocSnuggles +1 per C# Interactive window> new[] { ".jpg", ".exe", ".gif" }.Contains(".GIF") false and > new[] { ".jpg", ".exe", ".gif" }.Contains(".GIF", StringComparer.OrdinalIgnoreCase) truePriebe
it is better to return array FilesInfo[], not collection, cause original method also returns n array:Nitrification
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(); } }Nitrification
S
74

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");
Studnia answered 8/11, 2010 at 13:53 Comment(1)
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));Karren
L
61

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();
Lapse answered 20/8, 2010 at 0:12 Comment(6)
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?)Sweaty
A closing bracket was missing, I fixed itLapse
Exactly.EnumerateFiles() is better at performance.Rhinehart
It would be faster to use a HashSet<string>.Studnia
@SLaks, perhaps, depending on the number of extensions... For only 3 extensions I don't think the difference is significant.Lapse
Worked for me, thanks.Domella
A
27

You can use LINQ Union method:

dir.GetFiles("*.txt").Union(dir.GetFiles("*.jpg")).ToArray();
Arva answered 17/8, 2011 at 18:21 Comment(4)
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.Honeyhoneybee
For me, having a single .xlsx file in the dir folder, the result is coming up as 2 .xlsx file with same nameBoiler
@Boiler how it can be? Union is performed on the different extensions.Arva
@Arva No idea, i have posted problem statement here. stackoverflow.com/q/72041497/9304804Boiler
C
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.

Cancan answered 20/8, 2010 at 0:15 Comment(2)
That will be very inefficient if there are many files in the directory...Lapse
I like this solution best because it's simple and easy to read.Buckshot
O
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.

Orvas answered 20/8, 2010 at 0:8 Comment(0)
S
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);
          }
Sweaty answered 20/8, 2010 at 1:37 Comment(1)
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 ?Lapse

© 2022 - 2024 — McMap. All rights reserved.