应先用os.Stat获取FileInfo,再通过fi.Mode()&0200!=0判断用户可写位是否置位;但该方法仅检查权限位,不反映实际可写性,真实场景需用os.OpenFile尝试打开验证。

用 os.Stat + FileInfo.Mode 判断文件权限是否包含可写位
Go 没有直接的 is_writable 函数,得靠解析文件模式位。核心逻辑是:先用 os.Stat 获取文件元信息,再检查 FileInfo.Mode() 返回值是否包含 os.FileMode(0200)(用户可写)或更宽松的 0020(组可写)、0002(其他可写)。注意这不是“运行时能否写”,而是“权限位是否打开”——实际写入仍可能因挂载只读、ACL、SELinux 等失败。
常见错误是只看 err != nil 就认为不可写,但 os.Stat 失败(比如文件不存在、无读权限)和“存在但不可写”是两回事。必须先确保 err == nil,再检查模式位。
示例判断用户是否具备写权限:
fi, err := os.Stat("/path/to/file")
if err != nil {
// 文件不存在或无法访问,不能简单等同于“不可写”
return false
}
return fi.Mode()&0200 != 0 // 用户可写位是否置位
用 os.OpenFile 尝试以 os.O_WRONLY|os.O_RDWR 打开更贴近真实写入场景
仅查权限位不够可靠,尤其在 NFS、FUSE 或容器环境中,权限位可能与实际行为不一致。最稳妥的方式是模拟一次最小写操作:用 os.OpenFile 尝试以只写或读写模式打开,成功即说明当前进程可写(至少能获取文件句柄)。
立即学习“go语言免费学习笔记(深入)”;
关键点:
- 用
os.O_WRONLY | os.O_CREATE会创建文件,不适合检查已有文件;应优先用os.O_WRONLY或os.O_RDWR - 务必调用
file.Close(),否则可能泄漏 fd - 如果文件被其他进程独占锁住(如 Windows 上被记事本打开),
OpenFile也会失败,这属于真实不可写场景
简短示例:
f, err := os.OpenFile("/path/to/file", os.O_WRONLY, 0)
if err != nil {
return false // 打开失败,基本可判定当前不可写
}
f.Close()
return true
注意 os.IsPermission 和 os.IsNotExist 的区分场景
当 os.OpenFile 或 os.Stat 返回错误时,需要区分错误类型才能准确归因。例如:
-
os.IsPermission(err)表示权限拒绝(比如有读权限但没写权限) -
os.IsNotExist(err)表示路径根本不存在,此时谈“可写”无意义 - 其他错误(如
io.ErrClosed、网络超时)需单独处理,不能一概视为不可写
别直接用 err != nil 当作“不可写”的充分条件。真实业务中,常需组合判断:
_, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
// 文件不存在,可考虑创建?还是报错?
} else if os.IsPermission(err) {
// 权限不足,明确提示用户 chmod 或换路径
}
}
Windows 下需额外注意 ACL 和只读属性
在 Windows 上,文件系统权限模型比 Unix 更复杂:os.FileMode 的 0200 位始终为 false(Go 运行时忽略该位),且文件可能被标记为“只读属性”(FILE_ATTRIBUTE_READONLY),即使 ACL 允许写入也会失败。
因此在 Windows 上,仅靠 os.Stat().Mode() 判断必然不准。必须用 os.OpenFile 实测,或者调用 syscall 获取原生属性(不跨平台)。多数项目选择统一走 OpenFile 路径,避免分支逻辑。
另外,Windows 的符号链接和重解析点可能绕过权限检查,而 Go 的 os.Stat 默认跟随链接——若需检查链接本身而非目标,要用 os.Lstat。
os.Stat 返回的 mode 往往是挂载端的视图,而写入能力取决于服务端策略。真要保障可靠性,得在关键路径上做一次小写入测试(比如写 1 字节再删掉),而不是只信权限位或 OpenFile 成功。


















