82

Is there a way to simplify this linq expression, or is there a better way of doing this?

Directory.GetFiles(dir, "*.*", SearchOption.AllDirectories) .Where(s => s.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) || s.EndsWith(".gif", StringComparison.OrdinalIgnoreCase) || s.EndsWith(".png", StringComparison.OrdinalIgnoreCase) || ...); 

Basically I want to return all files of a certain extension. Unfortunately, this method isn't very flexible. I'd rather be able to add extensions to a list and have Directory.GetFiles return those extensions. Is that possible?

2

3 Answers 3

130

If you would like to do your filtering in LINQ, you can do it like this:

var ext = new List<string> { "jpg", "gif", "png" }; var myFiles = Directory .EnumerateFiles(dir, "*.*", SearchOption.AllDirectories) .Where(file => ext.Contains(Path.GetExtension(file).TrimStart('.').ToLowerInvariant())); 

Now ext contains a list of allowed extensions; you can add or remove items from it as necessary for flexible filtering.

Sign up to request clarification or add additional context in comments.

5 Comments

I can perform tests, but do you know which one would be more efficient?
Interesting that it works... From the documentation on GetFiles, it doesn't seem like it would accept the | like you would expect from a regex. The docs say it only recognizes * and ?, but hey, if it works, it works =)
Note: This doesn't seem to work on Win7 x64 running .NET 4.5. Throws Illegal characters in path due to the pipe.
@SimonWhitehead Never mind, I misinterpreted a piece of code in a post on Microsoft's web site, where a similarly-named method has been interpreting the pipes internally. I removed the non-working part of the solution (and SSL checked only the first one).
Note for the passerby: you might get a performance boost out of the newer .NET 4.0 Directory.EnumerateFiles as mentioned in answer by @nekizalb
37

Doesn't the Directory.GetFiles(String, String) overload already do that? You would just do Directory.GetFiles(dir, "*.jpg", SearchOption.AllDirectories)

If you want to put them in a list, then just replace the "*.jpg" with a variable that iterates over a list and aggregate the results into an overall result set. Much clearer than individually specifying them. =)

Something like...

foreach(String fileExtension in extensionList){ foreach(String file in Directory.GetFiles(dir, fileExtension, SearchOption.AllDirectories)){ allFiles.Add(file); } } 

For .NET 4+: if your directories are large, using EnumerateFiles instead of GetFiles can potentially be more efficient

3 Comments

Please be aware of the fact that while using wildcard * there is always chance that you can mess up the intended logic . For instance you have two files Test1.xls and Test2.xlsx and if you use filter *.xls to filter out xls file , Directory.GetFiles ** returns both xls as well as xlsx files **. [Read MSDN for more info]: msdn.microsoft.com/en-us/library/ms143316%28v=vs.110%29.aspx
effectively, xls and xlsx are the same file that modern day Excel can read?
@ina It's not an issue for Excel, it's an issue for other systems that try to read Excel data. But yes it's an exceedingly rare edge case.
12

I would have done using just a single line like:

List<string> imageFiles = Directory.GetFiles(dir, "*.*", SearchOption.AllDirectories).Where(file => new string[] { ".jpg", ".gif", ".png" }.Contains(Path.GetExtension(file))).ToList(); 

1 Comment

This works, of course, but the lambda expression you pass to .Where() will create one string[] every time it's invoked; that is, for every file under dir. If dir is, say, @"C:\" then this could potentially create tens or hundreds of thousands of short-lived "garbage" arrays. I definitely think it'd be worth it to define your array outside of .Where(), even if it means having to write that dreaded second line of code.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.