How to filter Directory.EnumerateFiles with multiple criteria?
string path = "C:\\";
var result = new List<string>();
string[] extensions = { ".mp3", ".wma", ".mp4", ".wav" };
foreach (string file in Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories)
.Where(s => extensions.Any(ext => ext == Path.GetExtension(s))))
{
result.Add(file);
Console.WriteLine(file);
}
I created some helper methods to solve this which I blogged about earlier this year.
One version takes a regex pattern \.mp3|\.mp4
, and the other a string list and runs in parallel.
public static class MyDirectory
{ // Regex version
public static IEnumerable<string> GetFiles(string path,
string searchPatternExpression = "",
SearchOption searchOption = SearchOption.TopDirectoryOnly)
{
Regex reSearchPattern = new Regex(searchPatternExpression, RegexOptions.IgnoreCase);
return Directory.EnumerateFiles(path, "*", searchOption)
.Where(file =>
reSearchPattern.IsMatch(Path.GetExtension(file)));
}
// Takes same patterns, and executes in parallel
public static IEnumerable<string> GetFiles(string path,
string[] searchPatterns,
SearchOption searchOption = SearchOption.TopDirectoryOnly)
{
return searchPatterns.AsParallel()
.SelectMany(searchPattern =>
Directory.EnumerateFiles(path, searchPattern, searchOption));
}
}
The most elegant approach is probably:
var directory = new DirectoryInfo(path);
var masks = new[] { "*.mp3", "*.wav" };
var files = masks.SelectMany(directory.EnumerateFiles);
But it might not be the most efficient.
As I noted in a comment, while Mikael Svenson's helper methods are great little solutions, if you're ever trying to do something for a one-off project in a hurry again, consider the Linq extension .Union( ). This allows you to join together two enumerable sequences. In your case, the code would look like this:
List<string> result = Directory.EnumerateFiles(path,"*.mp3", SearchOption.AllDirectories)
.Union(Directory.EnumerateFiles(path, ".wma", SearchOption.AllDirectories)).ToList();
This creates and fills your result list all in one line.