Go语言删文件或目录须区分os.Remove(仅限文件或空目录)和os.RemoveAll(递归删除整个目录树),并严格校验路径安全性、类型及权限,否则易误删或静默失败。

Go 语言删文件不能只调用 os.Remove 就完事——它不处理非空目录、不解决 Windows 文件占用、也不校验路径安全性,直接上生产容易误删或静默失败。
os.Remove 删不了非空目录,报 directory not empty 是正常行为
这个错误不是 bug,是设计使然。os.Remove 只接受两类目标:文件,或空目录。传入 "./logs" 这种含子文件的目录,必然失败。
- 想删单个配置文件(如
"config.yaml")或已知清空的缓存目录(如"./tmp/empty"),用os.Remove没问题 - 若不确定目录是否为空,别硬试——先用
os.ReadDir(path)检查长度,再决定调用哪个函数 - 错误判断必须用
errors.Is(err, syscall.ENOTEMPTY)或errors.Is(err, fs.ErrInvalid),别靠字符串匹配"not empty"
os.RemoveAll 会递归删整个树,但没回滚、不跳过失败项
os.RemoveAll 是唯一能删掉 "./dist" 这类构建产物目录的函数,但它不会“尽力而为”:遇到第一个权限拒绝或文件被占用,就立刻中止,前面删掉的文件不会恢复。
- Windows 下常见于编辑器(VS Code、GoLand)或杀毒软件锁住了某个
.exe或日志文件,此时可加重试逻辑(sleep + chmod + retry,最多 2–3 次) - Linux/macOS 上删不掉常因父目录无写权限,检查命令:
ls -ld /path/to/parent,不是看文件本身的权限 - 路径末尾带不带
/完全不影响行为,os.RemoveAll("build")和os.RemoveAll("build/")效果一致
删除前不校验路径,可能删到 /etc 或 ../config.yaml
Go 不做路径合法性过滤,os.RemoveAll("../config.yaml") 如果当前工作目录在 /home/user/project,实际删的是 /home/user/config.yaml。
立即学习“go语言免费学习笔记(深入)”;
- 用户输入或配置项来的路径,必须先过白名单:用
filepath.Abs转成绝对路径,再用strings.HasPrefix(abs, allowRoot)限定范围(如只允许删/tmp/myapp/下) - 禁止
..和绝对路径开头:if filepath.IsAbs(input) || strings.Contains(input, "..")就直接拒绝 - 测试时一律用
os.MkdirTemp("", "test-*")创建隔离目录,defer os.RemoveAll(dir)收尾,避免污染本地环境
符号链接和跨平台路径拼接最容易踩坑
os.Remove 和 os.RemoveAll 对符号链接的操作逻辑统一:只删链接本身,不碰它指向的目标。但路径拼接如果手写 "dir" + "file.txt",在 Linux 下会变成 "dirile.txt",根本找不到。
- 所有路径拼接必须用
filepath.Join("dir", "file.txt"),它自动适配/或 - 要删软链指向的目标,得先
os.Readlink(path)拿真实路径,再os.Remove;但更常见的是“删链接或它指向的东西”,这时需os.Lstat判断类型 - Windows 下长路径(>260 字符)可能触发
ERROR_FILENAME_EXCED_RANGE,建议用\?前缀(需手动加,Go 标准库不自动补)
真正麻烦的从来不是“怎么删”,而是“删之前有没有确认这是该删的、能删的、安全删的”。尤其在 CI/CD 或管理后台里,一个没校验的路径参数,可能让 os.RemoveAll 把整个部署目录卷走。


















