C# Glob模式匹配文件 C#如何使用类似*.txt的通配符模式查找文件

3次阅读

Directory.getfiles仅支持和?,不支持*递归匹配;需用directory.enumeratefiles+searchoption.alldirectories实现递归,或引入microsoft.extensions.filesystemglobbing支持完整glob语法。

C# Glob模式匹配文件 C#如何使用类似*.txt的通配符模式查找文件

Directory.GetFiles 支持 *?,但不支持 ** 递归匹配

windowsDirectory.GetFiles 默认只在单层目录下工作,"*.txt" 能匹配当前目录的文本文件,但 "**/*.txt" 会直接报错或返回空数组——它根本不认识双星号。这是最常被当成“Glob”用却翻车的第一步。

实操建议:

  • 要查当前目录:用 Directory.GetFiles("path", "*.log")
  • 要查子目录(一层):得手动拼路径,比如 Directory.GetFiles("path/sub", "*.log")
  • 真要 ** 效果?必须自己遍历或换库,.NET 6+ 的 Directory.EnumerateFiles 配合 SearchOption.AllDirectories 是更靠谱的替代方案

.NET 6+ 推荐用 Directory.EnumerateFiles + SearchOption.AllDirectories

这个组合才是实际项目里兼顾性能和语义的解法:EnumerateFiles 延迟执行、内存友好,AllDirectories 补上了 GetFiles 缺失的递归能力。但它依然只认 *?,不是 POSIX 风格的 Glob(比如不支持 {a,b}[abc])。

常见错误现象:传入 "**/*.cs" 还是只返回空——因为底层 Win32 API 不解析 **,它只是把整个字符串当字面文件名去搜。

实操建议:

  • 递归查所有 .cs 文件:Directory.EnumerateFiles("src", "*.cs", SearchOption.AllDirectories)
  • 想排除 binobj 目录?得自己过滤:.Where(p => !p.Contains("bin") && !p.Contains("obj"))
  • 注意路径分隔符:Windows 用 ,但代码里写 "src***.cs" 没用;统一用 /Path.Combine 构造路径更安全

需要完整 Glob 语法(如 **[a-z]{x,y})?上 Microsoft.Extensions.FileSystemGlobbing

这是 ASP.NET Core 内部用的库,也是目前 .NET 生态里唯一正经支持多段 Glob 模式的官方方案。它不操作磁盘,只做路径匹配,所以必须配合 Directory.GetFilesEnumerateFiles 一起用。

容易踩的坑:

  • 包名是 Microsoft.Extensions.FileSystemGlobbing,不是 Microsoft.AspNetCore.*,别装错
  • PatternMatchingResult 不是布尔值,要检查 .HasMatches 字段,而不是直接 if (result)
  • 模式里的 ** 必须单独成段,"src/**/Models/*.cs" 合法,"src/**Models/*.cs" 不合法

简短示例:

var matcher = new Matcher(); matcher.AddInclude("src/**/Models/*.cs"); var files = Directory.EnumerateFiles("src").Where(p => matcher.Match(p).HasMatches);

跨平台要注意 DirectorySeparatorChar 和大小写敏感性

linux/macos 下文件系统默认区分大小写,"*.TXT" 在 Windows 上能匹配 readme.TXT,但在 Linux 上可能完全漏掉。而且 / 在模式字符串里不是自动转换的。

实操建议:

  • 写模式时统一用 /,再用 Path.GetFullPathPath.Combine 转为目标平台格式
  • 如果目标是跨平台工具(比如 CLI),别依赖 Directory.GetFiles 的隐式行为,显式指定 SearchOption.TopDirectoryOnly 并自己处理递归
  • 对大小写不确定?用 StringComparer.OrdinalIgnoreCase 自己比对扩展名,比依赖通配符更可控

真正麻烦的从来不是怎么写 "*.cs",而是你写的那个 "**" 到底被谁解释、在哪一层解释、是否被截断——多数时候问题不在语法,而在你默认了某个环节“应该懂”。

text=ZqhQzanResources