ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

.NET 文件系统 Globbing 实战指南:深入 Microsoft.Extensions.FileSystemGlobbing 的 Matcher 模式匹配引擎

.NET 文件系统 Globbing 实战指南:深入 Microsoft.Extensions.FileSystemGlobbing 的 Matcher 模式匹配引擎 .NET 文件系统 Globbing 实战指南深入 Microsoft.Extensions.FileSystemGlobbing 的 Matcher 模式匹配引擎【免费下载链接】runtime.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.项目地址: https://gitcode.com/GitHub_Trending/runtime6/runtimeMicrosoft.Extensions.FileSystemGlobbing 是 .NET 运行时仓库中用于按 Glob 模式匹配文件系统名称/路径的官方组件其核心类型Matcher支持通过AddInclude(string)/AddExclude(string)声明包含与排除规则再对指定根目录执行匹配从而一次性获得符合规则的文件集合。它被广泛应用于构建工具、测试框架与 CLI 中用于筛选源文件、排除bin/obj产物、统计文档等场景。读完本文你将掌握该库的完整 Glob 语法、Matcher全部公开 API 的用法、Path/Stem的语义差异以及从模式解析PatternBuilder到目录遍历MatcherContext与状态机PatternContext的底层实现原理并可直接在自己的 .NET 项目中落地使用。一、库定位与快速上手该程序集位于 src/libraries/Microsoft.Extensions.FileSystemGlobbing官方 README 的定义只有一句话This assembly provides support for matching file system names/paths using glob patterns——即专门解决用通配符模式挑选文件这一件事API 面非常克制核心类型就是Matcher。1.1 最小可用示例参考 PACKAGE.md 给出的官方示例最简单的用法是using Microsoft.Extensions.FileSystemGlobbing; Matcher matcher new(); matcher.AddIncludePatterns(new[] { *.txt, *.asciidoc, *.md }); string searchDirectory ../starting-folder/; IEnumerablestring matchingFiles matcher.GetResultsInFullPath(searchDirectory); // matchingFiles 中的文件为完全限定的绝对路径这段代码完成三件事创建Matcher→ 批量添加三个包含模式 → 在指定根目录执行匹配并返回绝对路径集合。整个过程约 5 行代码这就是该库的典型工作流配置模式 → 执行 → 消费结果。1.2 核心 API 一览根据 ref/Microsoft.Extensions.FileSystemGlobbing.cs 中的公开契约库对外暴露以下主要类型类型职责Matcher承载包含/排除模式并执行匹配核心入口MatcherExtensions批量添加模式、内存匹配、返回绝对路径等扩展方法PatternMatchingResult匹配结果含Files与HasMatchesFilePatternMatch单个匹配项含Path与StemInMemoryDirectoryInfo不触碰磁盘的内存目录抽象Abstractions.*DirectoryInfoBase/FileInfoBase/FileSystemInfoBase及Wrapper适配器二、Glob 模式语法完全手册Matcher的 XML 文档见 src/Matcher.cs对模式语法做了最权威的说明这是理解该库行为的第一手资料以下完整整理。2.1 精确名称匹配直接写目录与文件名的精确路径模式含义one.txt根目录下名为one.txt的文件dir/two.txtdir目录下的two.txt2.2 单层通配符**匹配零到多个字符但不跨越目录分隔符即不匹配/模式含义*.txt所有.txt扩展名文件*.*所有带扩展名的文件*顶层目录中的所有文件.*以.开头的文件名隐藏文件*word*文件名中包含word的所有文件readme.*名为readme、任意扩展名的文件styles/*.cssstyles/目录下所有.css文件scripts/*/*scripts/下及仅一层的子目录中的文件images*/*名称以images开头或等于的文件夹中的文件注意scripts/*/*只深入一层子目录若要任意深度需用下面的**。2.3 任意深度递归/**/**表示任意目录深度模式含义**/*任意子目录中的全部文件dir/**/*dir/下任意层级子目录中的全部文件2.4 相对路径与父目录模式是相对于Execute(DirectoryInfoBase)传入的根目录而言的模式含义../shared/*根目录同级兄弟层级的shared目录下的所有文件2.5 目录模式与后缀递归源码还揭示了两类值得注意的隐藏规则见 PatternBuilder.cs以/结尾的模式按目录处理PatternBuilder.Build会先TrimEnd掉尾部斜杠再补上/**因此compiler/等价于compiler/**会匹配compiler目录下的全部文件。测试 FunctionalTests.cs 的 FolderInclude 验证了这一点。**.txt后缀递归当**与后缀连写时PatternBuilder会识别**.前缀L97-L108把**解析为递归段、剩余部分作为通配段继续解析因此**.txt表示任意目录层级下的.txt文件对应测试 RecursiveSuffixSearch。*.*归一化*.*会被改写为*L56-L64。2.6..的合法位置限制..只能出现在模式开头。若在中间使用PatternBuilder会直接抛出异常PatternBuilder.csArgumentException: .. can be only added at the beginning of the pattern.同时Match测试套件FunctionalTests.cs展示了../../lib/**/*.cs、../project2/**/*.cs这类跨目录模式的真实匹配结果说明多级父目录是受支持且被充分测试的。三、Matcher 核心 API 详解Matcher的完整实现位于 src/Matcher.cs。3.1 构造函数与大小写语义public Matcher() // 默认 OrdinalIgnoreCase public Matcher(StringComparison comparisonType) // 指定比较方式 public Matcher(StringComparison comparisonType StringComparison.OrdinalIgnoreCase, bool preserveFilterOrder false) // 完整签名三个要点默认不区分大小写无参构造委托到StringComparison.OrdinalIgnoreCaseL110-L113。仅支持 Ordinal 语义ComparisonType会传给PatternBuilder并最终流入各PathSegment。其中WildcardPathSegment构造器对比较类型做了强校验——只接受Ordinal与OrdinalIgnoreCase传入CurrentCulture等会抛出InvalidOperationException见 WildcardPathSegment.cs。preserveFilterOrder控制过滤顺序false默认时所有包含模式先于所有排除模式应用true时严格按添加顺序逐条应用 include/excludeL138-L146。内部实现上前者使用_includePatterns_excludePatterns两个独立列表后者使用统一的_includeOrExcludePatterns有序列表并在Execute时选择不同的MatcherContext构造路径L202-L204——顺序模式走PreserveOrderCompositePatternContext默认模式走IncludesFirstCompositePatternContext见 MatcherContext.cs。3.2 AddInclude / AddExcludepublic virtual Matcher AddInclude(string pattern); // 添加包含模式 public virtual Matcher AddExclude(string pattern); // 添加排除模式两个方法都返回Matcher自身支持链式调用L161-L191例如Matcher matcher new(); matcher.AddInclude(**/*.cs) .AddInclude(../../lib/**/*.cs) .AddExclude(**/obj/**) .AddExclude(**/bin/**);AddIncludePatterns/AddExcludePatterns扩展方法支持一次性传入多个模式分组见 MatcherExtensions.csmatcher.AddIncludePatterns(new[] { *.cs, *.md }, new[] { docs/**/*.md });3.3 Execute 与结果对象public virtual PatternMatchingResult Execute(DirectoryInfoBase directoryInfo);Execute接收一个DirectoryInfoBase抽象默认可由DirectoryInfoWrapper包装真实DirectoryInfo返回PatternMatchingResult。PatternMatchingResultsrc/PatternMatchingResult.cs结构非常简单IEnumerableFilePatternMatch Files匹配到的文件集合bool HasMatches是否有任何匹配Execute即使无匹配也始终返回实例而非 nullL197。注意Execute只匹配文件不返回目录本身目录仅作为递归遍历的中间节点。四、结果语义Path 与 Stem 的区别每个匹配项是FilePatternMatch结构体src/FilePatternMatch.cs包含两个极易混淆的属性官方文档用同一组例子做了精确说明Path相对于匹配模式起点的完整路径。Stem相对于模式中第一个通配符位置的子路径。官方示例若模式为src/Project/**/*.cs并匹配到src/Project/Interfaces/IFile.cs则Path src/Project/Interfaces/IFile.csStem Interfaces/IFile.cs。Stem的实际价值在于当用**/*.cs匹配后Stem直接给出的是通配部分的路径可用于重建相对结构。测试套件对此有系统验证例如 StemCorrectWithDifferentWildCards 与跨多层级目录的 StemIncludesAllSegmentsFromPatternStartingAtWildcard_OneDirectoryDeep可看到dir1/**/*.1匹配dir1/dir2/test.2时Stem dir2/test.2而**/dir1/**/*.1的Stem dir1/dir2/test.2——Stem 从第一个通配符起算的规则清晰可见。FilePatternMatch还实现了IEquatableFilePatternMatch相等性基于Path与Stem的不区分大小写比较L52-L56。五、扩展方法与三种执行方式MatcherExtensionssrc/MatcherExtensions.cs提供了四个高频扩展5.1 GetResultsInFullPath —— 磁盘扫描 绝对路径public static IEnumerablestring GetResultsInFullPath(this Matcher matcher, string directoryPath);内部用DirectoryInfoWrapper包装DirectoryInfo后调用Execute再把每个匹配项拼接为绝对路径返回无匹配时返回空集合而非 nullL55-L70。5.2 Match —— 纯内存匹配不触碰磁盘public static PatternMatchingResult Match(this Matcher matcher, string file); public static PatternMatchingResult Match(this Matcher matcher, string rootDir, string file); public static PatternMatchingResult Match(this Matcher matcher, IEnumerablestring? files); public static PatternMatchingResult Match(this Matcher matcher, string rootDir, IEnumerablestring? files);Match系列将文件列表直接喂给InMemoryDirectoryInfoL113-L118在内存中完成匹配。这对在真实磁盘之外验证模式、对已知文件清单做过滤如构建系统已有文件快照非常有用。InMemoryDirectoryInfosrc/InMemoryDirectoryInfo.cs内部会做路径归一化将备选分隔符统一为平台分隔符、Path.GetFullPath规范化并维护从文件列表派生的目录层级L62-L82。测试 StemCorrectWithDifferentWildCards_WithInMemory 证明了内存匹配与磁盘匹配在结果上的一致性。var matcher new Matcher(); matcher.AddInclude(src/project/**/*.cs); var files new[] { src/project/source1.cs, src/project/sub/source2.cs, other/ignored.cs }; PatternMatchingResult result matcher.Match(./, files); Console.WriteLine(result.HasMatches); // True Console.WriteLine(result.Files.Count()); // 2六、底层原理模式如何被解析与执行理解实现能帮你预测边界行为。整个执行管线由四个内部层次构成全部位于 src/Internal 下。6.1 PatternBuilder模式 → 段SegmentPatternBuilder.BuildPatternBuilder.cs把模式字符串按/、\切分为路径段逐段归类为四种IPathSegment段类型识别条件含义RecursiveWildcardSegment**任意深度目录ParentPathSegment..父目录仅开头合法CurrentPathSegment.当前目录解析时被忽略L165-L168LiteralPathSegment无通配符的纯文本段精确匹配WildcardPathSegment含*的段前缀/包含/后缀三段式匹配含*的段会被拆解为BeginsWithContains[]EndsWith三个部分L111-L158。WildcardPathSegment.Match的实现非常直白高效WildcardPathSegment.cs先校验长度下限再StartsWith前缀、EndsWith后缀最后用IndexOf依次定位每个中间子串——这正是*不跨越目录分隔符语义的来源因为段本身已经按分隔符切开。最终产物分为两类模式LinearPattern不含**的固定层级模式对应PatternContextLinearRaggedPattern含**的模式被拆为StartsWith/Contains/EndsWith三段组对应PatternContextRaggedL217-L264。6.2 MatcherContext深度优先遍历MatcherContext.ExecuteMatcherContext.cs从根目录开始深度优先递归对所有模式上下文PushDirectory(directory)压栈每个模式维护独立的目录匹配状态栈Declare()收集本轮可预期的字面量段用于剪枝优化若存在字面量目录段则只枚举名称匹配的子目录否则枚举全部文件系统项L74-L90对文件逐个Test通过则记录FilePatternMatch同时计算Stem对通过测试的子目录递归深入最后PopDirectory()恢复状态。这种声明式剪枝Declare机制使得形如dir/**/*.cs的模式在dir之前的目录层级无需全量枚举即可快速跳过无关目录是性能关键。6.3 PatternContext帧式状态机PatternContextTFramePatternContext.cs是所有模式上下文的基类核心是StackTFrame状态栈PushDirectory复制当前帧、推进匹配位置后压栈PopDirectory还原。这是典型的回溯式 DFS 状态管理。线性上下文PatternContextLinear.csFrame.SegmentIndex记录已匹配到的段位置目录名与当前段不匹配时标记IsNotApplicable该分支后续全部剪枝CanProduceStem为 true 的段开始累积StemItems。不规则上下文PatternContextRagged.cs处理**后的任意深度回溯用BacktrackAvailable记录**可回溯的目录层数SegmentGroupIndex在StartsWith → Contains → EndsWith各组间推进直到命中EndsWith组才允许文件Test通过。TestMatchingGroup会从当前目录沿父链倒序比对一组段L162-L182实现后缀组的匹配。6.4 组合上下文include/exclude 的汇合默认模式下所有包含模式与排除模式被聚合进IncludesFirstCompositePatternContext先应用全部 include再应用全部 excludepreserveFilterOrder: true时改用PreserveOrderCompositePatternContext按添加顺序逐个判定见 MatcherContext.cs。这正是 3.1 节所述过滤顺序语义的代码落点。七、典型场景示例7.1 模拟 gitignore排除构建产物Matcher matcher new(); matcher.AddInclude(**/*.*) .AddExclude(obj) .AddExclude(bin) .AddExclude(.*); // 排除隐藏文件/目录 foreach (string path in matcher.GetResultsInFullPath(./src/project)) { Console.WriteLine(path); }该组合正是测试 FolderExclude 覆盖的场景——obj、bin目录及其下所有文件都不会出现在结果中。7.2 收集指定后缀文档并保留相对结构Matcher matcher new(); matcher.AddInclude(**/*.md); PatternMatchingResult result matcher.Execute( new DirectoryInfoWrapper(new DirectoryInfo(./docs))); foreach (FilePatternMatch match in result.Files) { // Path 含完整相对路径Stem 为第一个通配符之后的相对路径 Console.WriteLine(${match.Path} (stem: {match.Stem})); }八、大小写、顺序与跨平台注意事项大小写默认不敏感需要敏感匹配时显式传StringComparison.Ordinal。测试 IncludeCaseSensitive / IncludeCaseInsensitive 给出了同模式下两种语义的完整对照如Source1.cs在 Ordinal 下不匹配source1.cs在 OrdinalIgnoreCase 下匹配。FilePatternMatch的相等性比较同样是 OrdinalIgnoreCase。过滤顺序需要先排除再包含等精确语义时使用preserveFilterOrder: true否则默认的include 优先、exclude 兜底通常已足够。分隔符模式中/与\均可作为分隔符PatternBuilder的_slashes同时包含两者且结果路径统一使用/拼接MatcherContext.CombinePath保证跨平台一致性。路径前缀模式以/开头会被TrimStart忽略./当前目录段会被静默丢弃../父目录段允许但仅限模式开头。九、源码导航与部署若想深入阅读推荐按以下顺序浏览公开 API 契约ref/Microsoft.Extensions.FileSystemGlobbing.cs入口与扩展src/Matcher.cs、src/MatcherExtensions.cs结果类型src/PatternMatchingResult.cs、src/FilePatternMatch.cs解析与执行引擎Internal/Patterns/PatternBuilder.cs、Internal/MatcherContext.cs、Internal/PathSegments、Internal/PatternContexts内存匹配src/InMemoryDirectoryInfo.cs测试佐证tests/FunctionalTests.cs、tests/PatternMatchingTests.cs、tests/PatternContexts部署方面Microsoft.Extensions.FileSystemGlobbing以独立 NuGet 包形式发布它属于 Microsoft.Extensions 系列库之一仓库层面的维护策略新功能、新 API、性能改进以及针对该库的新源码分析器均被接受见 libraries/README.md 的贡献标准。在项目中只需dotnet add package Microsoft.Extensions.FileSystemGlobbing即可引入该库面向 .NET Standard / 现代 .NET 多目标框架见 Microsoft.Extensions.FileSystemGlobbing.csproj。结语Microsoft.Extensions.FileSystemGlobbing 用一套精简的公开 API 包装了不简单的内部引擎PatternBuilder把模式编译为可执行的段序列MatcherContext以带剪枝的深度优先遍历扫描目录PatternContext系列以帧式状态机支撑线性模式与含**的 Ragged 模式的统一匹配。掌握了语法手册、Path/Stem语义与preserveFilterOrder等关键开关后你便能在构建工具、测试筛选、文件清单过滤等场景中稳定地驾驭它并借助仓库内的测试用例验证任何边界行为。【免费下载链接】runtime.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.项目地址: https://gitcode.com/GitHub_Trending/runtime6/runtime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表