414

I am trying to use the Directory.GetFiles() method to retrieve a list of files of multiple types, such as mp3's and jpg's. I have tried both of the following with no luck:

Directory.GetFiles("C:\\path", "*.mp3|*.jpg", SearchOption.AllDirectories);
Directory.GetFiles("C:\\path", "*.mp3;*.jpg", SearchOption.AllDirectories);

Is there a way to do this in one call?

lahsrah
  • 9,013
  • 5
  • 37
  • 67
Jason Z
  • 13,122
  • 15
  • 50
  • 62
  • 5
    As a side note , using GetFiles search pattern for filtering the extension is not safe.For instance you have two file Test1.xls and Test2.xlsx and you want to filter out xls file using search pattern *.xls, but GetFiles return both Test1.xls and Test2.xlsx . [Read Note Section for more info](http://msdn.microsoft.com/en-us/library/ms143316%28v=vs.110%29.aspx) – kiran Dec 07 '13 at 05:54
  • So how to prevent this? – Brackets Jul 12 '17 at 19:09
  • 4
    @kiran How is that not safe? That looks like a feature rather than a bug. – Kyle Delaney Jun 15 '18 at 13:05
  • 1
    So how to prevent this? Use ?.xls will correctly filter xls files only and will not, for example, include xlsx files. – Dave Oct 28 '20 at 04:55

28 Answers28

618

For .NET 4.0 and later,

var files = Directory.EnumerateFiles("C:\\path", "*.*", SearchOption.AllDirectories)
            .Where(s => s.EndsWith(".mp3") || s.EndsWith(".jpg"));

For earlier versions of .NET,

var files = Directory.GetFiles("C:\\path", "*.*", SearchOption.AllDirectories)
            .Where(s => s.EndsWith(".mp3") || s.EndsWith(".jpg"));

edit: Please read the comments. The improvement that Paul Farry suggests, and the memory/performance issue that Christian.K points out are both very important.

Community
  • 1
  • 1
Christoffer Lette
  • 14,346
  • 7
  • 50
  • 58
  • 71
    Just make sure that you understand the implications though: this will return *all* files in a string array and then filter that by the extensions you specify. That might not be a big issue if "C:\Path" doesn't have lot of files underneath it, but may be a memory/performance issue on "C:\" or something like that. – Christian.K Feb 14 '10 at 12:13
  • 28
    ... 2 years later: Nice code, but watch out with this, if you have a file that ends with .JPG it won't make it. Better add `s.ToLower().Endswith...` – Stormenet May 05 '10 at 09:35
  • 116
    you could just use `s.EndsWith(".mp3", StringComparison.OrdinalIgnoreCase)` – Paul Farry May 31 '10 at 22:58
  • To cut down on the or conditions I like to do the following (although I'm not sure if there is more of a performance impact)... var files = myDirInfo.GetFiles().Where(o => new[]{"mp3", "jpg"}.Contains(o.Extension.ToLower()).ToArray(); – Matt Winward Oct 26 '11 at 11:39
  • 132
    Note that with .NET 4.0, you can replace `Directory.GetFiles` with `Directory.EnumerateFiles`, http://msdn.microsoft.com/en-us/library/dd383571.aspx, which will avoid the memory issues that @Christian.K mentions. – Jim Mischel Dec 02 '11 at 22:58
  • @MattWinward you should read http://msdn.microsoft.com/en-us/library/dd465121.aspx – phoog Jan 15 '13 at 06:15
  • 2
    I made some performance improvements and provide comparison code at the answer below: http://stackoverflow.com/questions/163162/can-you-call-directory-getfiles-with-multiple-filters/19961761#19961761 – drzaus Nov 13 '13 at 18:40
  • 1
    @MAC It's the parameter of the lambda expression, in this case `s` represents each file name returned from the call to `Directory.EnumerateFiles`/`Directory.GetFiles`. – Christoffer Lette Jul 10 '15 at 11:30
  • Do you have a .Net 2 solution please? – Fandango68 Mar 15 '16 at 01:05
  • How does one check whether a file name (not its directory) contains a particular string? – Christine Jul 13 '16 at 17:46
  • 10
    If you want to improve performance even further in case of many possible extensions, it's better to create a HashSet with all extensions and do `Where(f => _validExtensions.Contains(Path.GetExtension(f).ToLower()))`. Basically `Contains` is much faster than performing string comparisons multiple times. – Ilya Chernomordik Aug 21 '16 at 18:19
  • GetFiles method is much faster than EnumerateFiles – Ashitosh birajdar Nov 29 '16 at 10:23
  • In context of data, you first want all files then you filter them. – Marek Bar Jul 09 '18 at 11:02
  • @IlyaChernomordik: The problem with .Contains is it includes files that have no extension. – Nick Westgate Aug 10 '18 at 04:37
  • 1
    Note that you may not always want to use `EnumerateFiles` rather than `GetFiles`; for example if you want to process the files in a specific order you want to have the whole file set to determine this order before you start processing. – d219 Jul 09 '20 at 14:33
68

How about this:

private static string[] GetFiles(string sourceFolder, string filters, System.IO.SearchOption searchOption)
{
   return filters.Split('|').SelectMany(filter => System.IO.Directory.GetFiles(sourceFolder, filter, searchOption)).ToArray();
}

I found it here (in the comments): http://msdn.microsoft.com/en-us/library/wz42302f.aspx

Albert
  • 1,062
  • 2
  • 13
  • 20
  • I'm guessing this avoids the potential memory pitfalls of the top rated answer? In which case, it should be rated higher! – Dan W Feb 01 '13 at 18:48
  • 14
    @DanW The top rated answer surely puts burden on the memory but I think that shouldn't be such a problem. I liked this answer too, but it's actually (much) slower then the accepted answer. Check this [SpeedTest](http://www.justmygame.net/wps/multiple-extensions/) – OttO Feb 13 '13 at 22:37
  • Thanks. Glad to see it's only about twice as slow - I'll stick with it for the meantime I think. – Dan W Feb 17 '13 at 19:47
  • 9
    It is only twice as slow if there are only two extensions. If you have a list of X extensions, then it will be X times more slow. Because here you are calling the function Directory.GetFiles several times, whereas in the other solution it is called only once. – Oscar Hermosilla May 12 '16 at 13:25
  • 1
    @OscarHermosilla One can use `Parallel.ForEach` to get them in parallel – FindOutIslamNow Jun 21 '18 at 12:22
  • 1
    @FindOutIslamNow but then you're limited by IO bandwidth – phuclv Jul 31 '19 at 09:24
  • @OttO bad link. – Arvo Bowen Mar 10 '20 at 19:58
41

If you have a large list of extensions to check you can use the following. I didn't want to create a lot of OR statements so i modified what lette wrote.

string supportedExtensions = "*.jpg,*.gif,*.png,*.bmp,*.jpe,*.jpeg,*.wmf,*.emf,*.xbm,*.ico,*.eps,*.tif,*.tiff,*.g01,*.g02,*.g03,*.g04,*.g05,*.g06,*.g07,*.g08";
foreach (string imageFile in Directory.GetFiles(_tempDirectory, "*.*", SearchOption.AllDirectories).Where(s => supportedExtensions.Contains(Path.GetExtension(s).ToLower())))
{
    //do work here
}
abatishchev
  • 98,240
  • 88
  • 296
  • 433
jnoreiga
  • 2,156
  • 19
  • 26
  • Help me with this please...When I print imageFile it's giving total path of it.How can I shrink it to just the name of the file. – Naresh May 24 '11 at 08:03
  • 2
    System.IO.Path.GetFileName(imageFile) – jnoreiga May 25 '11 at 17:43
  • `Path.GetExtension` returns '.ext', not '*.ext' (at least in 3.5+). – nullable Jan 04 '12 at 20:43
  • 2
    FYI: You need System.Linq for .where( – jnoreiga Mar 28 '12 at 21:20
  • Why use a comma as a separation character? A forbidden character like a | would be more reliable. You would exclude the (rare) case where an extension contains a comma at the end. – Ole EH Dufour Feb 21 '18 at 11:08
  • 2
    There is a potential flaw. We are long past the days where extensions are required to be exactly three characters. Suppose you might encounter a file with `.abc`, and supportedExtensions contains `.abcd`. Will match, though it should not. To fix: `supportedExtensions = ".jpg|.abcd|";` with `.Contains(Path.GetExtension(s).ToLower() + "|")`. That is, include your separator character in the test. IMPORTANT: your separator character must also be after the LAST entry in supportedExceptions. – ToolmakerSteve Apr 02 '18 at 13:10
  • Another flaw is that all .Contains solutions include files that have no extension. – Nick Westgate Aug 10 '18 at 04:32
35

for

var exts = new[] { "mp3", "jpg" };

You could:

public IEnumerable<string> FilterFiles(string path, params string[] exts) {
    return
        Directory
        .EnumerateFiles(path, "*.*")
        .Where(file => exts.Any(x => file.EndsWith(x, StringComparison.OrdinalIgnoreCase)));
}

But the real benefit of EnumerateFiles shows up when you split up the filters and merge the results:

public IEnumerable<string> FilterFiles(string path, params string[] exts) {
    return 
        exts.Select(x => "*." + x) // turn into globs
        .SelectMany(x => 
            Directory.EnumerateFiles(path, x)
            );
}

It gets a bit faster if you don't have to turn them into globs (i.e. exts = new[] {"*.mp3", "*.jpg"} already).

Performance evaluation based on the following LinqPad test (note: Perf just repeats the delegate 10000 times) https://gist.github.com/zaus/7454021

( reposted and extended from 'duplicate' since that question specifically requested no LINQ: Multiple file-extensions searchPattern for System.IO.Directory.GetFiles )

Community
  • 1
  • 1
drzaus
  • 24,171
  • 16
  • 142
  • 201
  • what do you mean by "i gets a bit faster if you don't have to turn them into globs"? Is it O(1) or is it O(n) (in regards to number of files, not number of extensions)? I would have guessed it's O(1) (or O(n) in regards to number of extensions) and probably somewhere in the range of a few cpu-cycles... If that's the case it's probably - performance wise - negligible – BatteryBackupUnit Jul 22 '14 at 12:39
  • @BatteryBackupUnit yeah with 10k reps against 2 extensions the glob vs. str difference is 3ms, so yes technically negligible (see perf results link), but not knowing how many extensions you need to filter for i figured it's worth pointing out that there is a difference; i leave it up to you to decide if "simplified usage" (i.e. `.FilterFiles(path, "jpg", "gif")`) is better than "explicit globs" (i.e. `.FilterFiles(path, "*.jpg", "*.gif")`). – drzaus Jul 23 '14 at 15:42
  • perfect, thanks. Sorry i somehow skipped over that github link. Maybe i should adapt my screen color settings :) – BatteryBackupUnit Jul 23 '14 at 18:46
  • Does this support uppercase extension such ass .JPG or .MKV? – Wahyu Apr 23 '16 at 07:18
  • @Wahyu You'll notice in my first example `StringComparison.OrdinalIgnoreCase` means it would work for `.jpg` or `.Jpg` or `.JPG`, etc – drzaus Apr 26 '16 at 19:45
  • 1
    The flaw with the SelectMany solution is that it will iterate over all the files once per file extension passed in. – 17 of 26 Sep 15 '16 at 13:12
  • @17of26 good call, thanks for pointing it out. It's funny because I just ran into this case yesterday as well, and only noticed because I had a bunch of files with "multiple extensions" (e.g. `.json.html`) that matched more than one glob. – drzaus Sep 17 '16 at 10:36
  • @17of26 But, I'm guessing/hoping that because it's more of a filesystem thing with the glob that it's not really iterating every file in the directory, at least not in the traditional sense. – drzaus Sep 17 '16 at 10:41
  • 1
    There's a gotcha with `EnumerateFiles` wherein matching 3-character extensions like `*.htm` will also match `*.html` or really anything that has .htm in it (e.g. `.htmfoo`). This seems to be related to old DOS 8.3 filenames. https://www.codeproject.com/Questions/152289/Directory-Get-Files-search-pattern-problem See note about searchPattern here: https://learn.microsoft.com/en-us/dotnet/api/system.io.directory.enumeratefiles?view=netframework-4.8 – Michael Haren Jan 25 '21 at 20:58
  • @MichaelHaren i can't reproduce that locally in LinqPad 6 or in https://dotnetfiddle.net/U1zkoI (v4.7.2) -- is it tied to a specific version of .NET? – drzaus Feb 08 '21 at 21:04
19

I know it's old question but LINQ: (.NET40+)

var files = Directory.GetFiles("path_to_files").Where(file => Regex.IsMatch(file, @"^.+\.(wav|mp3|txt)$"));
Icehunter
  • 241
  • 2
  • 5
  • 3
    Good idea. Consider using `file.ToLower()` to easily match upper-case extensions. And why not extract the extension first, so Regex doesn't have to examine entire path: `Regex.IsMatch(Path.GetExtension(file).ToLower(), @"\.(wav|mp3|txt)");` – ToolmakerSteve Apr 02 '18 at 13:17
16

There is also a descent solution which seems not to have any memory or performance overhead and be quite elegant:

string[] filters = new[]{"*.jpg", "*.png", "*.gif"};
string[] filePaths = filters.SelectMany(f => Directory.GetFiles(basePath, f)).ToArray();
Bas1l
  • 271
  • 1
  • 4
  • 6
  • 1
    I suppose I could edit it so that it would accept unknown unlimited number of extensions with new string variable and a Split function. But even then, how is this better than jnoreiga's solution? Is it faster? Less memory consuming? – Brackets Jul 12 '17 at 17:33
  • 1
    There is a trade-off. This approach calls GetFiles multiple times, one per filter. Those multiple calls *might* be significant "performance overhead" in some situations, It does have the important advantage that each GetFiles only returns an array with the *matching* file paths. I would expect this to *usually* be a good performance result, maybe even *superior* performance, but that needs to be tested. If GetFiles is significantly faster than EnumerateFiles, then this may be the best approach yet. Also note that the final ".ToArray()" can be omitted when IEnumerable is useable directly. – ToolmakerSteve Apr 02 '18 at 13:32
11

Another way to use Linq, but without having to return everything and filter on that in memory.

var files = Directory.GetFiles("C:\\path", "*.mp3", SearchOption.AllDirectories).Union(Directory.GetFiles("C:\\path", "*.jpg", SearchOption.AllDirectories));

It's actually 2 calls to GetFiles(), but I think it's consistent with the spirit of the question and returns them in one enumerable.

bluish
  • 26,356
  • 27
  • 122
  • 180
Dave Rael
  • 1,759
  • 2
  • 16
  • 21
  • Why use Linq, then? Would it be faster than using a List and addrange? – ThunderGr Nov 01 '13 at 13:16
  • 1
    i don't know what would be faster and don't think it's an important question. for almost any place you'd be using the code for any solution to this problem, the difference in performance would be negligible. the question should be as to what is more readable to ease the maintainability of the code in the future. i think this is a reasonable answer because it puts into one source line, which i think is part of what the question desires, the calls necessary and clearly expresses the intent of that line. list and addrange is distracting with multiple steps to accomplish the same thing. – Dave Rael Nov 01 '13 at 17:13
10

Let

var set = new HashSet<string>(
    new[] { ".mp3", ".jpg" },
    StringComparer.OrdinalIgnoreCase); // ignore case
var dir = new DirectoryInfo(path);

Then

dir.EnumerateFiles("*.*", SearchOption.AllDirectories)
   .Where(f => set.Contains(f.Extension));

or

from file in dir.EnumerateFiles("*.*", SearchOption.AllDirectories)
from ext in set // makes sense only if it's just IEnumerable<string> or similar
where String.Equals(ext, file.Extension, StringComparison.OrdinalIgnoreCase)
select file;
abatishchev
  • 98,240
  • 88
  • 296
  • 433
7

Nope. Try the following:

List<string> _searchPatternList = new List<string>();
    ...
    List<string> fileList = new List<string>();
    foreach ( string ext in _searchPatternList )
    {
        foreach ( string subFile in Directory.GetFiles( folderName, ext  )
        {
            fileList.Add( subFile );
        }
    }

    // Sort alpabetically
    fileList.Sort();

    // Add files to the file browser control    
    foreach ( string fileName in fileList )
    {
        ...;
    }

Taken from: http://blogs.msdn.com/markda/archive/2006/04/20/580075.aspx

NotMe
  • 87,343
  • 27
  • 171
  • 245
6

I can't use .Where method because I'm programming in .NET Framework 2.0 (Linq is only supported in .NET Framework 3.5+).

Code below is not case sensitive (so .CaB or .cab will be listed too).

string[] ext = new string[2] { "*.CAB", "*.MSU" };

foreach (string found in ext)
{
    string[] extracted = Directory.GetFiles("C:\\test", found, System.IO.SearchOption.AllDirectories);

    foreach (string file in extracted)
    {
        Console.WriteLine(file);
    }
}
abatishchev
  • 98,240
  • 88
  • 296
  • 433
eduardomozart
  • 1,444
  • 15
  • 14
5
DirectoryInfo directory = new DirectoryInfo(Server.MapPath("~/Contents/"));

//Using Union

FileInfo[] files = directory.GetFiles("*.xlsx")
                            .Union(directory
                            .GetFiles("*.csv"))
                            .ToArray();
Pankaj
  • 9,749
  • 32
  • 139
  • 283
5

in .NET 2.0 (no Linq):

public static List<string> GetFilez(string path, System.IO.SearchOption opt,  params string[] patterns)
{
    List<string> filez = new List<string>();
    foreach (string pattern in patterns)
    {
        filez.AddRange(
            System.IO.Directory.GetFiles(path, pattern, opt)
        );
    }


    // filez.Sort(); // Optional
    return filez; // Optional: .ToArray()
}

Then use it:

foreach (string fn in GetFilez(path
                             , System.IO.SearchOption.AllDirectories
                             , "*.xml", "*.xml.rels", "*.rels"))
{}
Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442
5
List<string> FileList = new List<string>();
DirectoryInfo di = new DirectoryInfo("C:\\DirName");

IEnumerable<FileInfo> fileList = di.GetFiles("*.*");

//Create the query
IEnumerable<FileInfo> fileQuery = from file in fileList
                                  where (file.Extension.ToLower() == ".jpg" || file.Extension.ToLower() == ".png")
                                  orderby file.LastWriteTime
                                  select file;

foreach (System.IO.FileInfo fi in fileQuery)
{
    fi.Attributes = FileAttributes.Normal;
    FileList.Add(fi.FullName);
}
abatishchev
  • 98,240
  • 88
  • 296
  • 433
  • `file.Extension.ToLower()` is bad practice. – abatishchev Jul 27 '12 at 14:35
  • then what we should use? @abatishchev – Nitin Sawant Jun 18 '13 at 10:56
  • @Nitin: `String.Equals(a, b, StringComparison.OrdinalIgnoreCase)` – abatishchev Jun 18 '13 at 17:34
  • 1
    Actually, file.Extension.Equals(".jpg",StringComparison.OrdinalIgnoreCase) is what I prefer. It seems to be faster than .ToLower or .ToUpper, or so they say everywhere I searched. Actually, .Equals is faster than ==, as well, since == calls .Equals *and* checks for null(Because you cannot do null.Equals(null)). – ThunderGr Nov 01 '13 at 13:19
5

If you are using VB.NET (or imported the dependency into your C# project), there actually exists a convenience method that allows to filter for multiple extensions:

Microsoft.VisualBasic.FileIO.FileSystem.GetFiles("C:\\path", Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, new string[] {"*.mp3", "*.jpg"});

In VB.NET this can be accessed through the My-namespace:

My.Computer.FileSystem.GetFiles("C:\path", FileIO.SearchOption.SearchAllSubDirectories, {"*.mp3", "*.jpg"})

Unfortunately, these convenience methods don't support a lazily evaluated variant like Directory.EnumerateFiles() does.

Crusha K. Rool
  • 1,502
  • 15
  • 24
4

The following function searches on multiple patterns, separated by commas. You can also specify an exclusion, eg: "!web.config" will search for all files and exclude "web.config". Patterns can be mixed.

private string[] FindFiles(string directory, string filters, SearchOption searchOption)
{
    if (!Directory.Exists(directory)) return new string[] { };

    var include = (from filter in filters.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries) where !string.IsNullOrEmpty(filter.Trim()) select filter.Trim());
    var exclude = (from filter in include where filter.Contains(@"!") select filter);

    include = include.Except(exclude);

    if (include.Count() == 0) include = new string[] { "*" };

    var rxfilters = from filter in exclude select string.Format("^{0}$", filter.Replace("!", "").Replace(".", @"\.").Replace("*", ".*").Replace("?", "."));
    Regex regex = new Regex(string.Join("|", rxfilters.ToArray()));

    List<Thread> workers = new List<Thread>();
    List<string> files = new List<string>();

    foreach (string filter in include)
    {
        Thread worker = new Thread(
            new ThreadStart(
                delegate
                {
                    string[] allfiles = Directory.GetFiles(directory, filter, searchOption);
                    if (exclude.Count() > 0)
                    {
                        lock (files)
                            files.AddRange(allfiles.Where(p => !regex.Match(p).Success));
                    }
                    else
                    {
                        lock (files)
                            files.AddRange(allfiles);
                    }
                }
            ));

        workers.Add(worker);

        worker.Start();
    }

    foreach (Thread worker in workers)
    {
        worker.Join();
    }

    return files.ToArray();

}

Usage:

foreach (string file in FindFiles(@"D:\628.2.11", @"!*.config, !*.js", SearchOption.AllDirectories))
            {
                Console.WriteLine(file);
            }
4

What about

string[] filesPNG = Directory.GetFiles(path, "*.png");
string[] filesJPG = Directory.GetFiles(path, "*.jpg");
string[] filesJPEG = Directory.GetFiles(path, "*.jpeg");

int totalArraySizeAll = filesPNG.Length + filesJPG.Length + filesJPEG.Length;
List<string> filesAll = new List<string>(totalArraySizeAll);
filesAll.AddRange(filesPNG);
filesAll.AddRange(filesJPG);
filesAll.AddRange(filesJPEG);
Pankaj
  • 9,749
  • 32
  • 139
  • 283
MattyMerrix
  • 10,793
  • 5
  • 22
  • 32
3

I wonder why there are so many "solutions" posted?

If my rookie-understanding on how GetFiles works is right, there are only two options and any of the solutions above can be brought down to these:

  1. GetFiles, then filter: Fast, but a memory killer due to storing overhead untill the filters are applied

  2. Filter while GetFiles: Slower the more filters are set, but low memory usage as no overhead is stored.
    This is explained in one of the above posts with an impressive benchmark: Each filter option causes a seperate GetFile-operation so the same part of the harddrive gets read several times.

In my opinion Option 1) is better, but using the SearchOption.AllDirectories on folders like C:\ would use huge amounts of memory.
Therefor i would just make a recursive sub-method that goes through all subfolders using option 1)

This should cause only 1 GetFiles-operation on each folder and therefor be fast (Option 1), but use only a small amount of memory as the filters are applied afters each subfolders' reading -> overhead is deleted after each subfolder.

Please correct me if I am wrong. I am as i said quite new to programming but want to gain deeper understanding of things to eventually become good at this :)

Janis
  • 436
  • 4
  • 12
3

Just found an another way to do it. Still not one operation, but throwing it out to see what other people think about it.

private void getFiles(string path)
{
    foreach (string s in Array.FindAll(Directory.GetFiles(path, "*", SearchOption.AllDirectories), predicate_FileMatch))
    {
        Debug.Print(s);
    }
}

private bool predicate_FileMatch(string fileName)
{
    if (fileName.EndsWith(".mp3"))
        return true;
    if (fileName.EndsWith(".jpg"))
        return true;
    return false;
}
Jason Z
  • 13,122
  • 15
  • 50
  • 62
3

Here is a simple and elegant way of getting filtered files

var allowedFileExtensions = ".csv,.txt";


var files = Directory.EnumerateFiles(@"C:\MyFolder", "*.*", SearchOption.TopDirectoryOnly)
                .Where(s => allowedFileExtensions.IndexOf(Path.GetExtension(s)) > -1).ToArray(); 
JohnnBlade
  • 4,261
  • 1
  • 21
  • 22
  • 1
    one issue with this code: if you have .xlsx in allowedFileExtensions, it will match .xlsx but also .xls and .xl and .x – 537mfb Jul 09 '21 at 09:47
2

I had the same problem and couldn't find the right solution so I wrote a function called GetFiles:

/// <summary>
/// Get all files with a specific extension
/// </summary>
/// <param name="extensionsToCompare">string list of all the extensions</param>
/// <param name="Location">string of the location</param>
/// <returns>array of all the files with the specific extensions</returns>
public string[] GetFiles(List<string> extensionsToCompare, string Location)
{
    List<string> files = new List<string>();
    foreach (string file in Directory.GetFiles(Location))
    {
        if (extensionsToCompare.Contains(file.Substring(file.IndexOf('.')+1).ToLower())) files.Add(file);
    }
    files.Sort();
    return files.ToArray();
}

This function will call Directory.Getfiles() only one time.

For example call the function like this:

string[] images = GetFiles(new List<string>{"jpg", "png", "gif"}, "imageFolder");

EDIT: To get one file with multiple extensions use this one:

/// <summary>
    /// Get the file with a specific name and extension
    /// </summary>
    /// <param name="filename">the name of the file to find</param>
    /// <param name="extensionsToCompare">string list of all the extensions</param>
    /// <param name="Location">string of the location</param>
    /// <returns>file with the requested filename</returns>
    public string GetFile( string filename, List<string> extensionsToCompare, string Location)
    {
        foreach (string file in Directory.GetFiles(Location))
        {
            if (extensionsToCompare.Contains(file.Substring(file.IndexOf('.') + 1).ToLower()) &&& file.Substring(Location.Length + 1, (file.IndexOf('.') - (Location.Length + 1))).ToLower() == filename) 
                return file;
        }
        return "";
    }

For example call the function like this:

string image = GetFile("imagename", new List<string>{"jpg", "png", "gif"}, "imageFolder");
Quispie
  • 948
  • 16
  • 30
2

Nop... I believe you have to make as many calls as the file types you want.

I would create a function myself taking an array on strings with the extensions I need and then iterate on that array making all the necessary calls. That function would return a generic list of the files matching the extensions I'd sent.

Hope it helps.

bluish
  • 26,356
  • 27
  • 122
  • 180
sebagomez
  • 9,501
  • 7
  • 51
  • 89
2

Using GetFiles search pattern for filtering the extension is not safe!! For instance you have two file Test1.xls and Test2.xlsx and you want to filter out xls file using search pattern *.xls, but GetFiles return both Test1.xls and Test2.xlsx I was not aware of this and got error in production environment when some temporary files suddenly was handled as right files. Search pattern was *.txt and temp files was named *.txt20181028_100753898 So search pattern can not be trusted, you have to add extra check on filenames as well.

WillyS
  • 31
  • 1
2
/// <summary>
/// Returns the names of files in a specified directories that match the specified patterns using LINQ
/// </summary>
/// <param name="srcDirs">The directories to seach</param>
/// <param name="searchPatterns">the list of search patterns</param>
/// <param name="searchOption"></param>
/// <returns>The list of files that match the specified pattern</returns>
public static string[] GetFilesUsingLINQ(string[] srcDirs,
     string[] searchPatterns,
     SearchOption searchOption = SearchOption.AllDirectories)
{
    var r = from dir in srcDirs
            from searchPattern in searchPatterns
            from f in Directory.GetFiles(dir, searchPattern, searchOption)
            select f;

    return r.ToArray();
}
bluish
  • 26,356
  • 27
  • 122
  • 180
A.Ramazani
  • 41
  • 1
2

Make the extensions you want one string i.e ".mp3.jpg.wma.wmf" and then check if each file contains the extension you want. This works with .net 2.0 as it does not use LINQ.

string myExtensions=".jpg.mp3";

string[] files=System.IO.Directory.GetFiles("C:\myfolder");

foreach(string file in files)
{
   if(myExtensions.ToLower().contains(System.IO.Path.GetExtension(s).ToLower()))
   {
      //this file has passed, do something with this file

   }
}

The advantage with this approach is you can add or remove extensions without editing the code i.e to add png images, just write myExtensions=".jpg.mp3.png".

Evado
  • 75
  • 1
  • 2
1

Or you can just convert the string of extensions to String^

vector <string>  extensions = { "*.mp4", "*.avi", "*.flv" };
for (int i = 0; i < extensions.size(); ++i)
{
     String^ ext = gcnew String(extensions[i].c_str());;
     String^ path = "C:\\Users\\Eric\\Videos";
     array<String^>^files = Directory::GetFiles(path,ext);
     Console::WriteLine(ext);
     cout << " " << (files->Length) << endl;
}
Pankaj
  • 9,749
  • 32
  • 139
  • 283
1

i don t know what solution is better, but i use this:

String[] ext = "*.ext1|*.ext2".Split('|');

            List<String> files = new List<String>();
            foreach (String tmp in ext)
            {
                files.AddRange(Directory.GetFiles(dir, tmp, SearchOption.AllDirectories));
            }
elle0087
  • 840
  • 9
  • 23
0

you can add this to your project

public static class Collectables {
    public static List<System.IO.FileInfo> FilesViaPattern(this System.IO.DirectoryInfo fldr, string pattern) {
        var filter = pattern.Split(" ");
        return fldr.GetFiles( "*.*", System.IO.SearchOption.AllDirectories)
            .Where(l => filter.Any(k => l.Name.EndsWith(k))).ToList();
    }
}

then use it anywhere like this

new System.IO.DirectoryInfo("c:\\test").FilesViaPattern("txt doc any.extension");
hossein sedighian
  • 1,711
  • 1
  • 13
  • 16
0

This is the shortest and performance wise the best solution:

            foreach (var FilePath in new[] { "*.fbx", "*.obj", "*.mtl" }.SelectMany(X => Directory.EnumerateFiles(DirectoryPath, X))) DoSomething(FilePath);
Xtro
  • 301
  • 2
  • 12