当前位置:首页 > 文章列表 > Golang > Go教程 > filepathGlob匹配分层文件名

filepathGlob匹配分层文件名

来源:17golang原创 2026-11-15 06:16:45 0浏览 收藏

Go 里用 filepath.Glob 匹配分层文件名时,最容易误判的是通配符的范围。比如 reports/*/*.json 只表示“reports 下的一层目录,再接一个 JSON 文件”,不会继续穿过第二层目录。目录层级固定时,直接把层级写进模式;层级不固定时,就用 filepath.WalkDir 遍历,再对文件名或相对路径做过滤。

官方文档:https://pkg.go.dev/path/filepath#Glob

filepath.Glob 固定目录层级的静态关系图
说明图:固定模式把 Glob、目录层级、通配符和 JSON 文件边界连接起来;它解释的是静态匹配关系,不是运行截图。

先把分层路径翻译成固定模式

把真实目录先写成树,再把每一段替换成模式,通常比直接试写通配符更稳。假设目录如下:

reports/
├── 2026/
│   ├── jan.json
│   └── feb.json
└── archive/
    └── 2025/
        └── dec.json

如果只想匹配 reports/2026/jan.json 这一层,可以使用 reports/*/*.json。这里第一个 * 匹配 2026,第二个 * 匹配 jan 或 feb。* 匹配的是不含路径分隔符的字符序列,因此它不会把 archive/2025 当成一个整体。

如果目标是 reports/archive/2025/dec.json,就要把两层目录明确写出来:reports/*/*.json 不能同时覆盖这条路径;可以使用 reports/*/*/*.json,但这会把层级固定为两层目录。filepath.Glob 没有 Bash ** 那种递归通配符语义。

用 Glob 读取结果并处理两类返回

Glob 返回匹配路径切片和错误。没有文件匹配时,结果是 nil 或空切片语义,不能当成系统故障;模式语法错误时,才会得到 filepath.ErrBadPattern。另外,遍历目录时发生的普通文件系统读取错误会被 Glob 忽略,所以它适合“尽力收集固定模式文件”,不适合要求报告每一个目录读取失败的场景。

package main

import (
	"errors"
	"fmt"
	"path/filepath"
)

func collectReports(root string) ([]string, error) {
	// 模式固定为:root 下的一层目录,目录中再找 JSON 文件。
	pattern := filepath.Join(root, "*", "*.json")
	matches, err := filepath.Glob(pattern)
	if err != nil {
		// 只有模式格式错误等 ErrBadPattern 才会从 Glob 返回。
		if errors.Is(err, filepath.ErrBadPattern) {
			return nil, fmt.Errorf("报告匹配模式无效: %w", err)
		}
		return nil, err
	}
	if len(matches) == 0 {
		// 无匹配是正常结果,由调用方决定是否降级或提示。
		return []string{}, nil
	}
	return matches, nil
}

这个函数把“无匹配”转换成空切片,把坏模式保留为错误。生产代码还可以根据业务需要排序;不要把返回顺序当成文件名排序契约。

为什么多写一层就匹配不到

问题通常不是 Glob 失效,而是模式表达的层数和目录真实层数不同。reports/*/*.json 的路径段可以拆成:固定的 reports、一个目录通配符、一个文件名通配符。如果真实文件是 reports/archive/2025/dec.json,中间多了一个目录段,模式自然不会命中。

Glob 与 WalkDir 的匹配边界静态关系图
说明图:固定层级模式与任意深度遍历是两种不同的结构关系;看左侧的 Glob 边界和右侧的 WalkDir、DirEntry、相对路径过滤关系。

不要用连续星号掩盖这个差异。Go 的 filepath.Match 规则里,* 不匹配路径分隔符;Glob 使用同一套模式语法。若需求是“所有后代目录中的 JSON”,应该明确换成遍历方案。

用 WalkDir 覆盖任意深度目录

WalkDir 适合层级不固定的目录树。遍历时先跳过目录项,再只对文件名做 filepath.Match("*.json", d.Name()),这样不会把路径分隔符交给文件名模式处理。下面的函数会收集任意深度下的 JSON 文件,并把遍历错误原样返回。

package reports

import (
	"fmt"
	"io/fs"
	"path/filepath"
)

func collectJSON(root string) ([]string, error) {
	var matches []string
	err := filepath.WalkDir(root, func(path string, d fs.DirEntry, walkErr error) error {
		// 目录读取失败要向上返回,不能把它伪装成“没有匹配”。
		if walkErr != nil {
			return walkErr
		}
		if d.IsDir() {
			return nil
		}
		matched, err := filepath.Match("*.json", d.Name())
		if err != nil {
			return fmt.Errorf("文件名模式无效: %w", err)
		}
		if matched {
			matches = append(matches, path)
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	return matches, nil
}

这里的取舍很明确:Glob 的代码短、边界固定、适合已知层级;WalkDir 能覆盖更深的目录,但要承担遍历成本,并自行决定忽略目录、权限错误和排序策略。

把模式选择收敛到一个收集入口

规模稍大后,最容易出现的是调用方各自拼接模式,最后有人用 Glob、有人手写递归,返回结果的错误语义也不一致。可以把固定层级和任意深度拆成两个明确入口:

package reports

import (
	"path/filepath"
	"sort"
)

func collect(root string, recursive bool) ([]string, error) {
	if !recursive {
		// 固定一层目录时使用 Glob,表达式直接反映目录契约。
		return filepath.Glob(filepath.Join(root, "*", "*.json"))
	}
	files, err := collectJSON(root)
	if err != nil {
		return nil, err
	}
	// 遍历顺序不作为 API 契约,统一排序便于后续生成批次。
	sort.Strings(files)
	return files, nil
}

调用方只需要决定目录层级是否固定,不必重复理解 Glob 的通配符边界。若文件集合很大,还可以在 WalkDir 回调里做前缀、扩展名或相对深度过滤,减少后续处理量。

几个容易踩到的边界

  • 只匹配文件名:filepath.Match("*.json", d.Name()) 不会检查完整路径;需要完整相对路径时,应先用 filepath.Rel 得到相对路径,再按固定层级设计模式。
  • 操作系统分隔符:文件系统路径用 filepath.Join 组合;不要把 URL 的斜杠规则和本地路径规则混在一起。
  • 结果为空:无匹配不是错误。只有业务明确要求至少一个文件时,才在收集函数外层把空结果转换成业务错误。
  • 需要可观测失败:若权限或目录读取失败必须被记录,就优先用 WalkDir,因为 Glob 会忽略访问文件系统时的普通错误。

速查:什么时候用哪种写法

需求推荐写法原因
固定一层目录中的 JSONfilepath.Glob(root/*/*.json)模式短,层级契约清晰
固定两层目录中的 JSONfilepath.Glob(root/*/*/*.json)显式表达两层目录
任意后代目录中的 JSONfilepath.WalkDir + filepath.Match不依赖不存在的递归 Glob
必须看到目录读取错误filepath.WalkDir回调可以接收并处理错误

记住一句话:filepath.Glob 解决的是“固定路径模式下有哪些匹配项”,不是“递归扫描整棵目录树”。先数清目录层级,再决定是把层级写进模式,还是把收集动作交给 WalkDir。

延伸问题

filepath.Glob 能直接用 ** 递归吗?

不能把它当作递归通配符使用。* 不跨路径分隔符;任意深度需求请使用目录遍历。

没有匹配文件时应该返回错误吗?

Glob 本身不会把无匹配当错误。是否报错取决于业务,例如“可选日报”可以返回空切片,“必须有配置”才应由业务层补充错误。

为什么 WalkDir 示例还要调用 Match?

WalkDir 负责访问目录树,Match 负责判断当前文件名是否符合规则。把职责拆开,就不会误以为 WalkDir 自带 Glob 模式。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
embed嵌入模板与静态资源embed嵌入模板与静态资源
上一篇
embed嵌入模板与静态资源
sqlTx封装可回滚事务
下一篇
sqlTx封装可回滚事务
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    1034次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    1033次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    1175次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    1139次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    979次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码