access() 是类 unix 系统判断路径读权限最直接方法,检查权限位与进程 uid/gid;windows 需结合令牌与 acl 核验,std::filesystem::status() 仅返回静态属性,不能替代运行时权限检查。

用 access() 判断路径读取权限最直接
在类 Unix 系统(Linux/macOS)上,access() 是判断当前进程对路径是否具有读权限的标准方法。它不依赖文件打开,只检查权限位和进程的有效用户/组 ID,开销小、语义明确。
常见错误是传入 R_OK 但忽略返回值为 -1 时的 errno 含义:返回 -1 不一定代表“无权限”,也可能是路径不存在(ENOENT)、不是目录却当作目录访问(ENOTDIR)或跨挂载点权限受限(EPERM)。
实操建议:
- 必须包含
<unistd.h></unistd.h>(POSIX)或<>cstdlib>(C++ 封装) - 调用前检查路径是否为空或以
/开头(相对路径易受CWD影响) - 若需区分“无权限”和“路径不存在”,需先用
stat()或opendir()验证路径存在性 - 示例:
if (access("/etc/passwd", R_OK) == 0) { // 可读 } else { switch (errno) { case EACCES: /* 明确权限拒绝 */ case ENOENT: /* 路径根本不存在 */ // ... } }
Windows 上要用 GetFileAttributes() + GetEffectiveToken()
Windows 没有 access() 的等价系统调用,GetFileAttributes() 只能查只读属性(FILE_ATTRIBUTE_READONLY),不能反映 ACL 控制的实际读取能力。真正可靠的判断必须结合访问令牌和 DACL。
多数场景下,直接尝试以只读方式打开文件更实际——因为即使 ACL 允许读,也可能因磁盘脱机、重解析点循环、符号链接跳转失败等导致无法读取。但若必须预判,核心步骤是:
- 调用
GetFileAttributesEx()确认路径存在且非目录(对文件)或可遍历(对目录) - 用
OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE)或OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY)获取当前令牌 - 调用
GetEffectiveToken()(需启用SE_PRIVILEGE_ENABLED)并用AccessCheck()核验GENERIC_READ权限 - 注意:UAC 提权后令牌可能不同,服务进程与交互式用户令牌也不同
std::filesystem::status() 不能替代权限检查
C++17 的 std::filesystem 提供了跨平台接口,但 status() 和 symlink_status() 返回的 file_status 只包含类型(regular_file、directory 等)和部分属性(如 owner_read),**不表示当前进程能否实际访问**。
原因在于:这些属性来自 stat() 系统调用的 st_mode 字段,仅反映文件自身的权限位,完全忽略 Linux 的 capability、SELinux 策略、Windows 的 ACL 继承规则等运行时策略。比如一个文件属主是 root、权限为 644,普通用户调用 status() 仍会看到 owner_read 为 true,但实际 access() 会返回 EACCES。
所以,不要用 is_regular_file(s) && (s.permissions() & std::filesystem::perms::owner_read) 做权限判断——这只能告诉你“文件写着可读”,不是“你能读”。
跨平台封装要注意权限粒度差异
Unix 的 R_OK 对应“读取文件内容”或“遍历目录”,而 Windows 的 GENERIC_READ 在目录上默认不包含遍历权(需显式请求 FILE_LIST_DIRECTORY)。这意味着同一段逻辑在两个平台行为可能不一致。
如果封装成统一函数,必须明确语义:
- 检查“能否打开该路径对应文件进行读取” → Unix 用
access(path, R_OK),Windows 用CreateFile(path, GENERIC_READ, ...)并立即CloseHandle() - 检查“能否列出该路径下子项” → Unix 仍用
access(path, R_OK)(对目录),Windows 必须用CreateFile(path, FILE_LIST_DIRECTORY, ...) - 避免使用
std::filesystem::exists()替代权限检查——它底层可能只做stat(),同样不保证可读
真正难的不是调用哪个函数,而是想清楚你要检查的是哪一层权限:文件系统级?ACL 级?还是策略引擎级?大多数应用只需要第一层,那就别绕远路。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











