go中判断文件可写/可执行需用fi.mode().perm()提取纯权限位再位与,如&0200≠0;os.stat仅读元数据,不保证实际可操作,真实访问能力应结合unix.access或直接操作+错误处理。

Go 里没有“文件是否可写/可执行”的布尔函数,必须自己解析 os.FileMode 的权限位;而安全校验不能只比哈希,得先确保读取过程没出错。
用 os.Stat + Perm() 提取纯权限位
直接调用 fi.Mode() 返回的是带文件类型的位掩码(比如目录、符号链接、设备文件等),高几位不是权限。不提取就直接位与,会误判。
- 永远用
fi.Mode().Perm()拿到低 9 位的纯 rwx 权限(0644、0755这种) - 检查用户可写:
fi.Mode().Perm()&0200 != 0 - 检查用户可执行:
fi.Mode().Perm()&0100 != 0 - 检查组可读:
fi.Mode().Perm()&0040 != 0 - 别用十进制
73或256这类数字硬写——八进制更直观,也和ls -l输出对齐
为什么 os.Stat 不等于“权限检查”
os.Stat 只告诉你元数据长什么样,不反映当前进程能否真正操作它。比如:
- 文件权限是
0644,但父目录不可写 → 你无法在该目录下创建新文件 - 挂载为只读(
mount -o ro)→ 所有写操作都会失败,哪怕Perm()显示可写 - Windows 下
Perm()恒为0444或0666,不反映真实 ACL,别依赖它做访问控制 - 错误类型不是只有
os.ErrNotExist:权限不足时返回os.ErrPermission,路径太深或 NFS 挂载失效也会报错
用 unix.access 做实际访问能力判断(仅 Linux/macOS)
如果你真要确认“当前进程现在能不能写这个路径”,golang.org/x/sys/unix 的 unix.access 更贴近 shell 的 [ -w ] 行为。
- 调用方式:
unix.Access(path, unix.W_OK),返回nil表示可写 - 注意:它检查的是整个路径(包括父目录),不是单个文件的 mode 位
- 不跨平台:Windows 下无此系统调用,编译会失败;macOS 需要
CGO_ENABLED=1 - 竞态条件依然存在:检查通过后,权限可能被其他进程立刻改掉 —— 所以多数场景仍建议“直接操作 + 错误处理”
文件完整性校验必须显式处理 io.Copy 错误
SHA256 校验不是“算完哈希再比对”就完事。空文件、磁盘断连、权限突变都发生在读取过程中,这些错误会被 io.Copy 返回,但容易被忽略。
- 别写
_, _ = io.Copy(h, f)—— 必须检查err - 空文件也要拦截:
n == 0 && err == nil是合法但危险的状态,应单独报错 - 哈希比对用
==安全,但前提是两个摘要都来自无错读取 - 生产环境一律用
sha256.New(),别用md5;且每个文件用新 hash 实例,复用会导致结果污染
真正难的不是怎么写那几行位运算,而是意识到:权限是动态的、分层的、受上下文约束的。一次 os.Stat 和一个哈希值,永远代替不了对操作意图和失败路径的诚实设计。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











