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

问题描述 投票:0回答:9

我有以下代码:

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 执行此操作的最有效方法是什么?有什么建议吗?

作为一名临时程序员,我希望得到任何帮助:-)

c# .net
9个回答
97
投票

我创建了一些辅助方法来解决这个问题,我在今年早些时候写了博客。

一个版本采用正则表达式模式

\.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));
   }
}

35
投票

最优雅的方法可能是:

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

但这可能不是最有效的。


22
投票
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);
}

16
投票

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

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

这会在一行中创建并填充您的结果列表。


7
投票

我是这样解决这个问题的:

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

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

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));
}

1
投票

对于使用与 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));
    }

0
投票

从.NET Core 2.1和.NET Standard 2.1开始,有内置类FileSystemName:文档源代码,它提供了匹配文件系统名称的方法:

示例:

public static IEnumerable<string> EnumerateFiles(string path, string[] searchPatterns, SearchOption searchOption = SearchOption.TopDirectoryOnly)
{
    return Directory.EnumerateFiles(path, "*", searchOption)
                    .Where(fileName => searchPatterns.Any(pattern => FileSystemName.MatchesSimpleExpression(pattern, fileName)));
}

我已经调整了 FileSystemName 的现有源代码以在 .NetFramework 4 中使用:Gist FileSystemName for .NetFramework 4


0
投票

使用正则表达式模式文件修改日期进行过滤。

在示例中返回的文件:

  • 名称以
    Bck
    开头,扩展名为
    tgz
    xml
  • 已超过
    200
    天。

返回完整路径名


string startPath = @"c:\temp";
int olderThanDays = 200;

Regex re = new Regex($@"^Bck.*\.tgz|^Bck.*\.xml");
var files = new DirectoryInfo(startPath)
    .EnumerateFiles($"*.*", SearchOption.AllDirectories)
    .Where(f => f.CreationTime > DateTime.Now.AddDays(-olderThanDays) && re.IsMatch(f.Name))             
    .Select(f => f.FullName).ToList();

© www.soinside.com 2019 - 2024. All rights reserved.