只写权限在文件系统中并不存在,windows和posix均不支持孤立的“只写”权限位;真正可行的判断方式是尝试以只写模式打开文件(linux用open(..., o_wronly|o_nonblock),windows用createfile(..., generic_write, ..., open_existing)),并捕获eacces或error_access_denied等错误。

只写权限在文件系统中并不存在
Windows 和 POSIX(Linux/macOS)文件系统都不支持“只写”这种孤立的权限位。所谓“只写”,意味着文件可写但不可读——这在底层设计上无法实现:写入操作(如 fopen(..., "w") 或 open(..., O_WRONLY))本身不依赖读权限,但实际使用中,绝大多数工具和 API 要求至少能获取文件元数据(比如检查是否存在、是否为普通文件),而这需要执行 stat() 或类似系统调用,而 stat() 在多数情况下需要目录的执行(x)权限,有时还隐式依赖读权限(例如遍历目录内容)。更关键的是:即使你设法绕过元数据检查直接打开写入,后续也无法验证写入是否成功(因为无法 read() 回来确认),也无法安全地判断该文件是否真被操作系统允许仅以写方式打开。
如何检查能否以只写模式打开文件
真正可行的判断方式不是查“只写属性”,而是尝试以只写方式打开文件,并捕获失败原因。C++ 标准库(std::fstream)默认不暴露底层错误码,所以需退回到 C 风格或系统 API:
- 在 Linux/macOS 上用
open(path.c_str(), O_WRONLY | O_NONBLOCK),检查返回值是否为 -1,再看errno是否为EACCES(权限拒绝)或ENOENT(路径不存在) - 在 Windows 上用
CreateFileA(path.c_str(), GENERIC_WRITE, ..., OPEN_EXISTING),失败时调用GetLastError(),关注ERROR_ACCESS_DENIED - 注意:即使
open()成功,也不能保证后续write()一定成功(例如磁盘满、配额超限、NFS 服务端拒绝等)
为什么 access(path, W_OK) 不够用
access() 只能告诉你进程是否有权写入该路径,但它无法区分是“可写入已有文件”还是“可在目录中创建新文件”。它也不反映文件是否被其他进程独占打开、是否位于只读挂载点(如 mount -o ro)、或是否受 ACL/SELinux 等扩展权限限制。更重要的是:access() 检查的是当前进程的有效 UID/GID,而实际打开文件时内核还会校验真实 UID、文件锁、强制访问控制策略等,二者结果可能不一致。
典型误判场景:
- 文件属主有
w权限,但所在文件系统挂载为ro→access(..., W_OK)返回 0,但open(..., O_WRONLY)失败 - 文件被另一个进程以
FILE_ATTRIBUTE_READONLY(Windows)或chattr +u(Linux)设为不可修改 →access()可能仍返回 0,但写入失败
跨平台检查建议与坑点
如果你必须做预检,推荐组合判断而非单靠一个 API:
- 先用
stat()/GetFileAttributes()确认路径存在且是常规文件(排除目录、符号链接、设备文件) - 再检查所在目录是否可写(因为写入文件本质是修改目录项)→ 对目录路径调用
access(dir_path.c_str(), W_OK)或GetFileAttributes(dir_path.c_str()) & FILE_ATTRIBUTE_DIRECTORY后判断权限 - 最后尝试最小化打开:
open(..., O_WRONLY | O_NOFOLLOW | O_CLOEXEC)(Linux)或CreateFile(..., GENERIC_WRITE, 0, ..., OPEN_EXISTING)(Windows),立即close(),不进行任何读写 - 避免用
std::ofstream构造函数做探测——它可能静默截断文件或创建新文件,副作用不可控
真正可靠的“只写能力”只能在实际写入时确定;所有预检都只是启发式猜测,且容易因 race condition 失效(比如检查完瞬间文件被 chmod 或 umount)。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











