我有以下代码:
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);
}
它工作正常,做我需要的。除了一件小事。我想找到一种更好的方法来过滤多个扩展。我想使用带有过滤器的字符串数组:
string[] extensions = { "*.mp3", "*.wma", "*.mp4", "*.wav" };
使用.NET Framework 4.0 / LINQ执行此操作的最有效方法是什么?有什么建议吗?
我很感激任何帮助成为偶尔的程序员: - )
答案 0 :(得分:75)
我在今年早些时候创建了一些帮助方法来解决这个问题,我blogged。
一个版本采用正则表达式模式\.mp3|\.mp4
,另一个版本采用字符串列表并且并行运行。
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));
}
}
答案 1 :(得分:25)
从LINQ上下文中删除,这归结为如何找出文件是否与扩展列表匹配。 System.IO.Path.GetExtension()
是比String.EndsWith()
更好的选择。多个||
可以替换为.Contains()
或.IndexOf()
,具体取决于集合。
var extensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{ ".mp3", ".wma", ".mp4", ".wav" };
... s => extensions.Contains(Path.GetExtension(s))
答案 2 :(得分:17)
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);
}
答案 3 :(得分:13)
最优雅的方法可能是:
var directory = new DirectoryInfo(path);
var masks = new[] { "*.mp3", "*.wav" };
var files = masks.SelectMany(directory.EnumerateFiles);
但它可能不是最有效的。
答案 4 :(得分:9)
正如我在评论中指出的那样,虽然Mikael Svenson的助手方法是很好的解决方案,但如果你想再次为一次性项目做点什么,请考虑Linq扩展 .Union( )即可。这允许您将两个可枚举的序列连接在一起。在您的情况下,代码将如下所示:
List<string> result = Directory.EnumerateFiles(path,"*.mp3", SearchOption.AllDirectories)
.Union(Directory.EnumerateFiles(path, ".wma", SearchOption.AllDirectories)).ToList();
这会在一行中创建并填充结果列表。
答案 5 :(得分:2)
我知道这是一篇很老的帖子,但我想出了一个人们可能想要使用的解决方案。
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));
}
答案 6 :(得分:1)
使用相同的File Extensions列表字符串作为GUI打开对话框进行过滤,例如:
".exe,.pdb".Split(',', ';', '|').SelectMany(_ => Directory.EnumerateFiles(".", "*" + _, searchOptions)
打包:
public static IEnumerable<string> EnumerateFilesFilter(string path, string filesFilter, SearchOption searchOption = SearchOption.TopDirectoryOnly)
{
return filesFilter.Split(',', ';', '|').SelectMany(_ => Directory.EnumerateFiles(path, "*" + _, searchOption));
}
答案 7 :(得分:0)
我这样解决了这个问题:
string[] formats = {".mp3", ".wma", ".mp4"};
foreach (var file in Directory.EnumerateFiles(folder, "*.*", SearchOption.AllDirectories).Where(x => formats.Any(x.EndsWith)))
{
// TODO...
}