filepath.ext 安全提取扩展名需先用 filepath.base 获取纯文件名,再判断最后一个点位置;直接调用易得空字符串或隐藏文件全名,如 ".gitignore" 或 "archive.tar.gz" 返回 ".gz" 而非 ".tar.gz"。

如何用 filepath.Ext 安全提取扩展名并避免空字符串陷阱
Go 的 filepath.Ext 并不总是返回你预期的 ".jpg" 这类结果——它会返回包括点在内的完整后缀,但对无扩展名文件(如 README)返回空字符串 "",对隐藏文件(如 .gitignore)返回 ".gitignore"(即整个文件名)。这会导致误删或漏删。
实际清理时应先做标准化判断:
- 用
strings.TrimLeft(filepath.Base(path), ".")检查是否为纯隐藏文件(开头是点且无其他点) - 用
ext := filepath.Ext(path); if ext == "" || ext == "."排除无扩展名和仅含点的路径 - 推荐组合:先
filepath.Base取文件名,再用正则^\.[^.]+$单独匹配隐藏文件,扩展名逻辑与之分离
遍历目录时怎样跳过系统保护路径和符号链接循环
filepath.WalkDir 是首选,但它默认不自动跳过 /proc、/sys 或挂载点;而 os.ReadDir + 递归虽可控,却容易在符号链接形成环时 panic。
关键控制点:
- 在
WalkDir的回调中,对每个fs.DirEntry调用entry.Type() & os.ModeSymlink != 0判断是否为符号链接,然后用os.Stat获取真实路径并缓存已访问的 inode(需用syscall.Stat_t.Dev和Ino组合去重) - 硬编码跳过路径前缀:
strings.HasPrefix(absPath, "/proc/") || strings.HasPrefix(absPath, "/sys/") - 不要依赖
entry.IsDir()判断是否进入——某些设备文件会伪装成目录,应先os.Lstat再检查Mode().IsDir()
os.Remove 失败时为什么不能只看 os.IsNotExist
批量删文件时常见错误是把所有非 os.IsNotExist 错误都当作严重异常终止流程。实际上,权限拒绝(os.IsPermission)、设备忙(unix.EBUSY)、正在被进程占用(unix.EBUSY 或 syscall.Errno(16))都应记录并继续,否则一次失败就中断整个清理任务。
建议处理方式:
- 对每个
os.Remove结果做细粒度判断:if err != nil { if os.IsNotExist(err) || os.IsPermission(err) { log.Printf("skip %s: %v", path, err); return } else { log.Printf("fail %s: %v", path, err) } } - 避免在循环里用
log.Fatal—— 它会直接退出,丢失后续可删文件 - Windows 下还要额外检查
err.Error()是否含"The process cannot access the file",这是杀毒软件锁文件的典型表现
如何让垃圾清除器支持 dry-run 和白名单校验
生产环境运行前必须能预览将删什么。硬编码白名单(如保留 .keep、.git 目录)比黑名单更安全,因为扩展名列表永远追不上新格式。
实操要点:
- 命令行加
-dry-run标志,所有os.Remove替换为log.Printf("[DRY] remove %s", path),不调用任何删除 API - 白名单检查放在扩展名匹配之后:
if isWhitelisted(path) { return },其中isWhitelisted应同时检查完整路径(如strings.HasSuffix(path, "/.git/config"))和 basename(如base == ".keep") - 扩展名过滤用
map[string]bool预加载,避免每次调用strings.HasSuffix—— 对.tmp这类短后缀,map查找快一个数量级
真正难的是识别“看似临时实为重要”的文件,比如 config.json.tmp 可能是编辑器原子写入的中间态。这类边界情况没法靠扩展名穷举,得靠修改时间窗口(如 fi.ModTime().Before(time.Now().Add(-24*time.Hour)))辅助判断,但时间本身也可能不准——别忘了 NFS 或虚拟机时钟漂移。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











