_access仅能粗略判断文件存在性或只读属性,不检查ACL等实际权限;跨平台应优先用std::filesystem::status()获取权限位,但最终I/O仍需直接尝试并捕获错误。

用 _access 检查文件是否存在或可读写,但别指望它返回完整权限
_access 是 Windows 下的 C 运行时函数(头文件 io.h),常被误当作“跨平台权限检测工具”。它只做三件事:判断文件是否存在(F_OK)、是否可读(R_OK)、是否可写(W_OK)。注意:_access 在 Windows 上不检查实际 ACL 或 owner/group 权限,而是看文件是否标记为只读(对普通文件)或目录是否可写(对目录)。Linux/macOS 的 access() 行为更接近 POSIX 语义,但仍不等价于 stat() 中的 st_mode 位。
常见错误现象:
- 在 Windows 上对一个 NTFS 文件调用
_access(path, W_OK)返回 0(成功),但后续fopen(..., "w")失败 —— 因为用户无 ACL 写权限,而文件本身未设只读属性 - 传入
X_OK检查可执行性,在 Windows 上始终返回 -1(不支持),即使文件是 .exe
实操建议:
- 仅用
_access做快速存在性或基础只读判断(如配置文件是否可读) - 不要用于安全敏感场景(比如决定是否加载动态库)
- 跨平台项目中,避免直接依赖
_access;改用std::filesystem::status()+ 权限位解析
std::filesystem::status() 获取原始权限位,但要注意平台差异
std::filesystem::status(path) 返回 std::filesystem::file_status,其 permissions() 成员给出底层 st_mode 中的权限位(如 owner_read、group_exec 等)。这是目前 C++ 标准中最可靠的权限信息来源。
立即学习“C++免费学习笔记(深入)”;
关键限制:
- Windows 上,
std::filesystem::perms仅映射 DOS 属性(只读/隐藏/系统/存档)和部分 NTFS ACL 的简化视图(例如,若用户有写权限但文件未设只读标志,则owner_write可能为 true;但若 ACL 明确拒绝,该位仍可能为 true ——status()不做实时访问检查) - Linux/macOS 上,
permissions()直接来自stat.st_mode & 0777,但不反映 capability 或 mount options(如noexec) -
status()不等价于access():它不模拟当前进程的有效 UID/GID,也不检查 capability 或 SELinux 策略
示例(检查 owner 是否可读写):
auto s = std::filesystem::status("config.txt");
auto p = s.permissions();
if ((p & std::filesystem::perms::owner_read) &&
(p & std::filesystem::perms::owner_write)) {
// 注意:这不保证 open() 一定成功
}
真正要验证“现在能不能打开写”,就老老实实试一下
所有静态权限检查(_access、status().permissions()、甚至 stat())都只是快照。文件可能被其他进程瞬时锁住、目录可能被挂载为只读、SELinux 可能拦截、甚至磁盘已满 —— 这些都无法靠读取元数据预判。
实操建议:
- 对关键 I/O 操作(如保存用户数据),直接尝试
std::ofstream或fopen(),捕获失败并处理errno(EACCES、EROFS、ENOSPC等) - 如果必须前置检查,组合使用:
std::filesystem::exists()+std::filesystem::is_regular_file()+status().permissions(),再加一句注释说明“这只是启发式检查” - 避免嵌套判断:比如先
_access(R_OK)再fopen("r")—— 多一次 syscall 且无实质增益,还引入竞态窗口
Windows 上特别注意:_access 和 _waccess 的路径编码
Windows 下 _access 接受窄字符路径(const char*),默认按当前 ANSI 代码页解码;而 _waccess 接受宽字符(const wchar_t*),走 UTF-16。如果你的路径含中文或 emoji,用 _access 很可能返回 -1(errno = EINVAL)。
实操建议:
- 优先用
_waccess并传入std::filesystem::path::c_str()(C++17 起path默认以 wide string 存储 Windows 路径) - 不要手动用
MultiByteToWideChar转换后再传给_access—— 路径已损坏 - 更推荐彻底弃用
_access,改用std::filesystem::status(),它内部自动处理路径编码问题
权限检查这件事,最易被忽略的其实是“检查完到真正操作之间的空窗期”。无论用哪个 API,只要没在同一个原子上下文中完成验证与使用,就都有失败可能。所以与其花精力拼凑各种检查,不如把错误处理写扎实。



















