C# 如何使用多个条件筛选Directory.Enumerate文件?

C# 如何使用多个条件筛选Directory.Enumerate文件?,c#,.net,C#,.net,我有以下代码: List<string> result = new List<string>(); foreach (string file in Directory.EnumerateFiles(path,"*.*", SearchOption.AllDirectories) .Where(s => s.EndsWith(".mp3") || s.EndsWith(".wma"))) { result

我有以下代码:

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);                 
       }
使用NETFramework4.0/LINQ最有效的方法是什么?有什么建议吗


作为一名临时程序员,我非常感谢任何帮助:-)

从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))
var extensions=newhashset(StringComparer.OrdinalIgnoreCase)
{.mp3“,.wma“,.mp4“,.wav”};
...  s=>extensions.Contains(Path.GetExtension)
string path=“C:\\”;
var result=新列表();
字符串[]扩展名={.mp3“,.wma“,.mp4“,.wav”};
foreach(目录.EnumerateFiles(路径“***”),SearchOption.AllDirectory中的字符串文件)
.Where(s=>extensions.Any(ext=>ext==Path.GetExtension(s)))
{
结果.添加(文件);
Console.WriteLine(文件);
}

我创建了一些帮助器方法来解决这个问题,这是我今年早些时候提到的

一个版本采用regex模式
\.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));
   }
}
公共静态类MyDirectory
{//Regex版本
公共静态IEnumerable GetFiles(字符串路径,
字符串searchPatternExpression=“”,
SearchOption SearchOption=SearchOption.TopDirectoryOnly)
{
Regex reSearchPattern=newregex(searchPatternExpression,RegexOptions.IgnoreCase);
返回目录.枚举文件(路径“*”,搜索选项)
.Where(文件=>
reSearchPattern.IsMatch(Path.GetExtension(文件));
}
//采用相同的模式,并并行执行
公共静态IEnumerable GetFiles(字符串路径,
字符串[]搜索模式,
SearchOption SearchOption=SearchOption.TopDirectoryOnly)
{
返回searchPatterns.AsParallel()
.SelectMany(searchPattern=>
枚举文件(路径、搜索模式、搜索选项));
}
}

我知道这是一篇老文章,但我提出了一个人们可能喜欢使用的解决方案

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));
}
private IEnumerable FindFiles()
{
DirectoryInfo sourceDirectory=newdirectoryinfo(@“C:\temp\mydirectory”);
字符串foldersFilter=“*bin*,*obj*”;
字符串文件类型过滤器=“*.mp3,*.wma,*.mp4,*.wav”;
//按文件夹名称和扩展名筛选
IEnumerable directories=foldersFilter.Split(',).SelectMany(模式=>sourceDirectory.EnumerateDirectories(模式,SearchOption.AllDirectories));
列表文件=新列表();
files.AddRange(directories.SelectMany(dir=>fileTypesFilter.Split(',).SelectMany(pattern=>dir.EnumerateFiles(pattern,SearchOption.AllDirectories)));
//拾取根文件
files.AddRange(fileTypesFilter.Split(',).SelectMany(pattern=>sourceDirectory.EnumerateFiles(fileTypesFilter,SearchOption.TopDirectoryOnly));
//按扩展过滤
IEnumerable files2=fileTypesFilter.Split(',).SelectMany(pattern=>sourceDirectory.EnumerateFiles(pattern,SearchOption.AllDirectories));
}

正如我在评论中提到的,虽然Mikael Svenson的助手方法是很小的解决方案,但是如果你再次尝试为一次性项目做一些事情,请考虑LINQ扩展<强> .Union()。这允许您将两个可枚举序列连接在一起。在您的情况下,代码如下所示:

List<string> result = Directory.EnumerateFiles(path,"*.mp3", SearchOption.AllDirectories)
.Union(Directory.EnumerateFiles(path, ".wma", SearchOption.AllDirectories)).ToList();
List result=Directory.EnumerateFiles(路径“*.mp3”、SearchOption.AllDirectories)
.Union(Directory.EnumerateFiles(路径“.wma”,SearchOption.AllDirectories)).ToList();

这将在一行中创建并填充结果列表。

最优雅的方法可能是:

var directory = new DirectoryInfo(path);
var masks = new[] { "*.mp3", "*.wav" };
var files = masks.SelectMany(directory.EnumerateFiles);

但是它可能不是最有效的。

对于使用与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));
    }
公共静态IEnumerable EnumerateFileFilter(字符串路径、字符串文件筛选器、SearchOption SearchOption=SearchOption.TopDirectoryOnly)
{
返回filesFilter.Split(“,”,“;”,“|”).SelectMany(=>Directory.EnumerateFiles(路径,“*”+,searchOption));
}

我这样解决了这个问题:

string[] formats = {".mp3", ".wma", ".mp4"};

foreach (var file in Directory.EnumerateFiles(folder, "*.*", SearchOption.AllDirectories).Where(x => formats.Any(x.EndsWith)))
{
    // TODO...
}

如果要与
*
进行字符串比较,则需要删除它们。另一个建议是使用允许不区分大小写检查的重载。可能最好使用哈希集和不区分大小写的比较。您需要包含点(.mp3)。使用string.ToLower()来处理大小写。@Hans,这个点是对的,但是ToLower()会比普通的大小写好吗?只是一个选择:你还需要“.mp3”,而不是“mp3”。谢谢你的作品完美。。。在我的情况下,我需要在之前添加.ToArray()。其中。。。如果没有这个,LINQ查询就不起作用了。你应该考虑并行运行每个扩展搜索。我在回答中创建了一些有用的助手方法。这是一个非常古老的问题(已经由@MikaelSvenson适当地回答了),但另一个选项是使用可枚举扩展名.Union(),如:foreach(Directory.EnumerateFiles(path,.mp3),SearchOption.AllDirectories)。Union(Directory.EnumerateFiles(path,.wma),SearchOption.AllDirectories)){…}感谢您的良好实现。什么是好的(高效的)最终在WPF屏幕上显示结果的方法?我计划使用您的并行方法来获取文件。如果我使用foreach迭代结果并将其存储在列表中,然后将其加载到屏幕上会怎么样?您可以只绑定到任一方法的输出,因为绑定将为您枚举所有结果。无需首先将其存储在单独的列表中。m最有效的方法是开始显示枚举的项目。我不是WPF专家,但我想是的
    public static IEnumerable<string> EnumerateFilesFilter(string path, string filesFilter, SearchOption searchOption = SearchOption.TopDirectoryOnly)
    {
        return filesFilter.Split(',', ';', '|').SelectMany(_ => Directory.EnumerateFiles(path, "*" + _, searchOption));
    }
string[] formats = {".mp3", ".wma", ".mp4"};

foreach (var file in Directory.EnumerateFiles(folder, "*.*", SearchOption.AllDirectories).Where(x => formats.Any(x.EndsWith)))
{
    // TODO...
}