用access()检查写权限最直接:在linux/macos上它按真实uid/gid验证路径写权限且无竞态;windows需用getfileattributes()结合路径类型判断,但无法反映acl;最终应以实际i/o操作及错误码为准。

用 access() 检查写权限最直接
在类 Unix 系统(Linux/macOS)上,access() 是检查文件写权限最轻量、最常用的方式。它不打开文件,只查询权限位,避免了竞态和资源开销。
关键点:传入 R_OK、W_OK 或 X_OK,但注意——W_OK 判断的是「当前进程是否能以写方式打开该路径」,不是单纯看文件的 w 位。比如目录有写权限但不可执行(chmod 200 dir),access(dir, W_OK) 仍会失败,因为无法进入目录创建文件。
-
access("path/to/file", W_OK)返回 0 表示可写;返回 -1 且errno == EACCES表示拒绝;errno == ENOENT表示路径不存在 - 不要用
stat()+ 手动判断st_mode,容易漏掉 setuid/setgid、ACL、挂载选项(如noexec、ro)等影响 - Windows 下
access()不检查 ACL,仅看 DOS 属性(FILE_ATTRIBUTE_READONLY),且对目录始终返回可写(即使实际不能创建文件)
Windows 上要用 GetFileAttributes() + 判断目录存在性
Windows 没有 POSIX 权限模型,access() 只能告诉你文件是否被标记为只读,但无法反映 NTFS ACL 或父目录权限。真正想确认「能否成功写入」,必须结合路径类型和属性:
- 对普通文件:检查
GetFileAttributes("path") & FILE_ATTRIBUTE_READONLY是否为 0 - 对目录:
GetFileAttributes()不提供写入能力信息,需尝试CreateFile()用GENERIC_WRITE打开并立即关闭(代价略高但可靠) - 如果路径不存在,
GetFileAttributes()返回INVALID_FILE_ATTRIBUTES,此时需逐级检查父目录是否存在且可写(否则创建会失败)
跨平台封装时别忽略「路径存在性」和「是否为目录」
很多 bug 出在把「文件可写」和「能在该路径写入」混为一谈。比如 /tmp/nonexistent.txt —— 文件不存在时 access(..., W_OK) 在 Linux 上可能成功(只要 /tmp 可写),但在 Windows 上 GetFileAttributes() 直接失败。
- 先用
stat()或GetFileAttributes()确认路径存在,再根据st_mode或返回值判断是文件还是目录 - 若目标是「创建新文件」,重点检查父目录权限;若目标是「覆盖现有文件」,才看文件自身属性
- C++20 的
std::filesystem::status()可统一获取类型和权限,但底层仍调用平台 API,且不暴露完整 ACL,生产环境慎用于权限决策
真实场景中建议「试操作」而非纯检查
权限检查永远滞后于实际状态。Umask 变更、挂载重映射、SELinux 策略更新、NFS 服务器端权限调整……都可能导致检查通过但写入失败。
- 对关键写入操作(如配置保存、日志轮转),直接
open()/fopen()并捕获错误,比预检更可靠 - 预检适合 UI 场景(如禁用保存按钮),但必须容忍「检查通过 → 实际失败」的情况,并给出明确错误提示(比如
"Permission denied: cannot write to /etc/config") - 不要在多线程/多进程环境中缓存检查结果——权限可能在两次调用间被其他进程修改
真正的难点不在怎么查,而在查完之后信不信、怎么容错。系统权限从来不是静态布尔值,而是动态策略的瞬时快照。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











