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

用 os.Stat + FileMode.Perm() 提取纯权限位
Go 里没有现成的 IsExecutable() 或 HasWritePermission() 这类函数,必须手动解析权限。直接调用 fi.Mode() 返回的是带文件类型(如目录、符号链接)的完整位掩码,高几位不是权限位,直接位与会误判。
正确做法是先调用 fi.Mode().Perm() 拿到低 9 位的纯 Unix 权限(即 0644、0755 这种八进制形式),再做位操作:
- 检查用户可读:
fi.Mode().Perm() & 0400 != 0 - 检查用户可写:
fi.Mode().Perm() & 0200 != 0 - 检查用户可执行:
fi.Mode().Perm() & 0100 != 0 - 永远用八进制字面量(
0400),别用十进制256或硬编码73——它和ls -l输出对齐,也更不易出错
os.Stat 不等于“我能操作这个文件”
os.Stat 只读元数据,不验证当前进程是否真能访问。比如:
- 文件权限是
0644,但父目录没x权限 → 你连open都失败(Linux/macOS 下进入目录需执行权限) - 挂载为只读(
mount -o ro)→ 所有写操作返回os.ErrPermission,哪怕Perm()显示可写 - Windows 下
Perm()恒为0444或0666,不反映真实 ACL,不能用于访问控制决策
所以,仅靠 os.Stat + Perm() 做预检,覆盖不了真实场景。多数服务应直接操作 + 错误处理,而非层层预判。
用 unix.Access 判断实际可访问性(Linux/macOS)
如果你确实需要模拟 shell 的 [ -w ] 行为(即“我现在能不能写这个路径”),golang.org/x/sys/unix 提供了 unix.Access(path, unix.W_OK):
- 返回
nil表示可写,它检查整条路径(含所有父目录)的访问能力 - 注意:不跨平台,Windows 下无法编译;macOS 需要
CGO_ENABLED=1 - 仍有竞态:检查通过后,权限可能被其他进程立刻改掉 —— 所以它适合诊断或友好报错,不适合替代真实 I/O
权限错误必须用 os.IsPermission 判断
遇到 open /path: permission denied,不能字符串匹配 "permission",必须用标准判断函数:
- 用
os.IsPermission(err)识别EACCES和EPERM - 如果用了 Go 1.13+,且错误被包装(如
fmt.Errorf("read %s: %w", path, err)),要用errors.Is(err, os.ErrPermission)更鲁棒 - 别在
defer里检查权限错误 —— 此时err可能已被覆盖或失效 - 常见陷阱:把
os.Stat返回的permission denied当作“文件不存在”,结果逻辑走偏;必须用errors.Is(err, os.ErrNotExist)明确区分
真正难的不是写对那几行位运算,而是意识到权限是动态的、分层的、受挂载选项和安全模块约束的 —— 预检只能辅助,落地仍得靠真实操作和细粒度错误分类。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











