如何使用多个条件过滤Directory.EnumerateFiles?

Yoo*_*kim 72 .net c#

我有以下代码:

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);                 
       }
Run Code Online (Sandbox Code Playgroud)

它工作正常,做我需要的.除了一件小事.我想找到一种更好的方法来过滤多个扩展.我想使用带有过滤器的字符串数组,例如:

string[] extensions = { "*.mp3", "*.wma", "*.mp4", "*.wav" };
Run Code Online (Sandbox Code Playgroud)

使用.NET Framework 4.0/LINQ执行此操作的最有效方法是什么?有什么建议?

我很感激任何帮助成为偶尔的程序员:-)

Mik*_*son 78

我创建了一些帮助方法来解决这个问题,我今年早些时候发表博客.

一个版本采用正则表达式模式\.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));
   }
}
Run Code Online (Sandbox Code Playgroud)


Hen*_*man 27

从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))
Run Code Online (Sandbox Code Playgroud)

  • 如果要与它们进行字符串比较,则需要删除`*`s. (2认同)
  • 您需要包含点(.mp3).使用string.ToLower()来处理大小写. (2认同)

Isl*_*ene 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);
}
Run Code Online (Sandbox Code Playgroud)


Tom*_*rek 14

最优雅的方法可能是:

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

但它可能不是最有效的.

  • 不错,但需要简短编辑:“masks.SelectMany(m =&gt; dinf.EnumerateFiles(m));”。 (3认同)
  • @AsenKasimov EnumerateFiles 方法有一个带有参数的重载,让您指定也在子文件夹内搜索。 (2认同)

Kir*_*iya 9

正如我在评论中指出的那样,虽然Mikael Svenson的辅助方法是很好的小解决方案,但如果你想再次为一次性项目做点什么,请考虑Linq扩展.Union().这允许您将两个可枚举的序列连接在一起.在您的情况下,代码将如下所示:

List<string> result = Directory.EnumerateFiles(path,"*.mp3", SearchOption.AllDirectories)
.Union(Directory.EnumerateFiles(path, ".wma", SearchOption.AllDirectories)).ToList();
Run Code Online (Sandbox Code Playgroud)

这会在一行中创建并填充结果列表.

  • 在 C# 中,每次使用扩展名模式进行两次(或更多)搜索可能比返回所有文件并按扩展名进行过滤的通用搜索要慢。不过,进行基准测试会很有趣。 (4认同)
  • 优雅,并避免C#枚举所有文件,允许文件系统优化,但它可以. (2认同)

小智 6

我这样解决了这个问题:

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

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