go 1.16+ 应优先用 filepath.walkdir 替代 filepath.walk,单层遍历用 os.readdir;注意路径拼接用 filepath.join、权限错误需检查、递归深度需手动限制、筛选逻辑应解耦预编译。

Go 1.16+ 应优先用 filepath.WalkDir,不是 filepath.Walk;单层目录直接用 os.ReadDir,别碰已废弃的 ioutil.ReadDir。
用 os.ReadDir 快速列出当前目录一级内容
它只读一层,不递归,返回 []fs.DirEntry,轻量且无额外系统调用。适合生成文件列表、检查子目录是否存在、或作为手动递归的起点。
-
entry.Name()拿文件名,entry.IsDir()判断类型,不用entry.Info()就能避开os.Stat开销 - 需要大小、修改时间等元信息?只对目标条目显式调用
os.Stat(entry.Name()),别全量调用 - 路径拼接必须用
filepath.Join(root, entry.Name()),硬拼"dir/" + name在 Windows 下会失效 - 遇到
os.ErrPermission时,os.ReadDir返回非 nil error,必须检查,否则后续遍历可能 panic
用 filepath.WalkDir 安全递归遍历整个目录树
这是 Go 1.16+ 的标准递归方案,比 filepath.Walk 更快(避免重复 os.Stat)、更可控(支持 filepath.SkipDir)、更健壮(对权限错误默认继续)。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 回调函数签名是
func(path string, d fs.DirEntry, err error) error,注意参数类型是fs.DirEntry,不是os.FileInfo - 跳过某个子目录(如
node_modules):在回调中检测d.IsDir() && d.Name() == "node_modules",然后return filepath.SkipDir - 过滤文件后缀推荐
strings.HasSuffix(d.Name(), ".go"),不用filepath.Ext(path)——后者对main.go.bak会误判为.bak - 遇到软链接环路或深度过大(如
/proc/self/fd)时,WalkDir不自动防护,需在回调里用闭包计数器限制递归深度,超限就return filepath.SkipDir
为什么别用 filepath.Walk?常见踩坑点
filepath.Walk 内部对每个路径都调用 os.Stat,在含大量小文件的目录下性能明显下降;它也不支持 filepath.SkipDir(旧版只能靠拼路径 + 提前 return 模拟),且对符号链接处理不如 WalkDir 明确。
- 错误处理易错:回调里若返回任意非 nil error(比如
errors.New("skip")),整个遍历立刻终止——但你本意可能只是跳过当前项 - 权限错误(如访问
/root/.ssh)时,err != nil传入回调,但Walk默认继续;若你在回调里没检查err就直接用info,会 panic - 想排除隐藏文件?得写
strings.HasPrefix(filepath.Base(path), "."),不能只看path开头——因为./.git和/home/user/.git都要匹配 - 跨平台路径比较务必先
filepath.Clean(path),否则./foo和foo被视为不同路径
筛选逻辑别塞进 Walk 回调里
把后缀匹配、大小范围、正则规则这些抽成独立函数,类型定义为 type Matcher func(path string, d fs.DirEntry) bool,方便组合与测试。
- 正则匹配必须预编译
*regexp.Regexp,别在每次回调里regexp.Compile,否则 CPU 直接拉满 - 多个条件组合用
&&或||,比如isGoFile && notInExcludedDir,而不是在回调里堆 if-else - 结果收集若大致知道规模(如项目下最多 5k 文件),用
make([]string, 0, 5000)预分配切片,避免频繁 realloc -
filepath.Match("*.md", d.Name())支持 shell 风格通配,比strings.HasSuffix更灵活(如需忽略大小写),但注意它不支持**递归匹配
真正麻烦的从来不是“怎么写遍历”,而是权限错误是否静默跳过、软链接会不会死循环、路径比较是否跨平台一致、以及筛选条件能不能随时增删改——这些细节不提前想清楚,上线后第一波报错八成出在这儿。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










