如何用多个条件过滤Directory.EnumerateFiles?
我有以下代码:
List<string> result = new List<string>(); foreach (string file in Directory.EnumerateFiles(path,"*.*", SearchOption.AllDirectories) .Where(s => s.EndsWith(".mp3") || s.EndsWith(".wma"))) { result.Add(file); }
它工作正常,做我所需要的。 除了一件小事。 我想find一个更好的方法来筛选多个扩展。 我想用这样的filter使用一个string数组:
string[] extensions = { "*.mp3", "*.wma", "*.mp4", "*.wav" };
什么是最有效的方式来使用NET框架4.0 / LINQ做到这一点? 有什么build议么?
我将不胜感激任何偶然的程序员的帮助:-)
我创build了一些帮助方法来解决这个问题,我在今年早些时候写了一些内容。
一个版本采用正则expression式模式\.mp3|\.mp4
,另一个版本是一个string列表,并行运行。
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)); } }
从LINQ上下文中剥离,这归结为如何找出文件是否匹配扩展名列表。 System.IO.Path.GetExtension()
是比String.EndsWith()
更好的select。 多重||
可以用.Contains()
或.IndexOf()
replace,具体取决于集合。
var extensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { ".mp3", ".wma", ".mp4", ".wav" }; ... s => extensions.Contains(Path.GetExtension(s))
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); }
最优雅的方法可能是:
var directory = new DirectoryInfo(path); var masks = new[] {"*.mp3", "*.wav"}; var files = masks.SelectMany(directory.EnumerateFiles);
但它可能不是最有效的。
正如我在评论中指出的那样,尽pipeMikael Svenson的辅助方法是一个很好的小解决scheme,但如果您曾经试图为一次性项目再次做一些事情,请考虑Linq extension .Union() 。 这使您可以将两个枚举序列连接在一起。 在你的情况下,代码将如下所示:
List<string> result = Directory.EnumerateFiles(path,"*.mp3", SearchOption.AllDirectories) .Union(Directory.EnumerateFiles(path, ".wma", SearchOption.AllDirectories)).ToList();
这将创build并填充您的结果列表中的所有行。
我知道这是一个旧的post,但我想出了一个人们可能会喜欢使用的解决scheme。
private IEnumerable<FileInfo> FindFiles() { DirectoryInfo sourceDirectory = new DirectoryInfo(@"C:\temp\mydirectory"); string foldersFilter = "*bin*,*obj*"; string fileTypesFilter = "*.mp3,*.wma,*.mp4,*.wav"; // filter by folder name and extension IEnumerable<DirectoryInfo> directories = foldersFilter.Split(',').SelectMany(pattern => sourceDirectory.EnumerateDirectories(pattern, SearchOption.AllDirectories)); List<FileInfo> files = new List<FileInfo>(); files.AddRange(directories.SelectMany(dir => fileTypesFilter.Split(',').SelectMany(pattern => dir.EnumerateFiles(pattern, SearchOption.AllDirectories)))); // Pick up root files files.AddRange(fileTypesFilter.Split(',').SelectMany(pattern => sourceDirectory.EnumerateFiles(fileTypesFilter, SearchOption.TopDirectoryOnly))); // filter just by extension IEnumerable<FileInfo> files2 = fileTypesFilter.Split(',').SelectMany(pattern => sourceDirectory.EnumerateFiles(pattern, SearchOption.AllDirectories)); }