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

Directory.GetFiles 支持 * 和 ?,但不支持 ** 递归匹配
Windows 的 Directory.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) - 想排除
bin和obj目录?得自己过滤:.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.GetFiles 或 EnumerateFiles 一起用。
容易踩的坑:
- 包名是
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.GetFullPath或Path.Combine转为目标平台格式 - 如果目标是跨平台工具(比如 CLI),别依赖
Directory.GetFiles的隐式行为,显式指定SearchOption.TopDirectoryOnly并自己处理递归 - 对大小写不确定?用
StringComparer.OrdinalIgnoreCase自己比对扩展名,比依赖通配符更可控
真正麻烦的从来不是怎么写 "*.cs",而是你写的那个 "**" 到底被谁解释、在哪一层解释、是否被截断——多数时候问题不在语法,而在你默认了某个环节“应该懂”。










