如何用C++17的std::filesystem模拟access函数检查文件读写权限
用C++17 std::filesystem模拟Unix access()的R_OK/W_OK检查
Unix的access()函数会结合进程身份、文件权限位、ACL等因素,检查进程实际能否访问文件;直接用std::filesystem::perms检查权限位无法覆盖所有场景,最准确的方式是实际尝试执行对应的访问操作,以下是具体实现:
模拟access(path, R_OK)(检查可读)
#include <filesystem> #include <fstream> namespace fs = std::filesystem; bool is_readable(const fs::path& path) { if (!fs::exists(path)) { return false; } if (fs::is_directory(path)) { // 目录可读:尝试获取目录迭代器,验证能否遍历目录内容 try { [[maybe_unused]] auto dir_it = fs::directory_iterator(path); return true; } catch (const fs::filesystem_error&) { return false; } } else { // 文件可读:尝试以只读模式打开 std::ifstream file(path, std::ios::in); return file.is_open(); } }
模拟access(path, W_OK)(检查可写)
#include <filesystem> #include <fstream> namespace fs = std::filesystem; bool is_writable(const fs::path& path) { if (!fs::exists(path)) { // 文件不存在时,检查父目录是否允许创建新文件 fs::path parent_dir = path.parent_path().empty() ? fs::current_path() : path.parent_path(); if (!fs::exists(parent_dir) || !fs::is_directory(parent_dir)) { return false; } try { fs::path temp_file = parent_dir / fs::unique_path(); std::ofstream temp_out(temp_file); if (temp_out.is_open()) { temp_out.close(); fs::remove(temp_file); return true; } return false; } catch (const fs::filesystem_error&) { return false; } } else { if (fs::is_directory(path)) { // 目录可写:尝试创建临时文件验证能否写入 try { fs::path temp_file = path / fs::unique_path(); std::ofstream temp_out(temp_file); if (temp_out.is_open()) { temp_out.close(); fs::remove(temp_file); return true; } return false; } catch (const fs::filesystem_error&) { return false; } } else { // 文件可写:以追加模式打开,避免截断原有内容 std::ofstream file(path, std::ios::out | std::ios::app); return file.is_open(); } } }
关键说明
- 避免直接检查权限位:
std::filesystem::perms仅返回文件的静态权限位,无法处理SUID/SGID、ACL、进程有效身份等场景,实际尝试访问是最符合access()逻辑的方式。 - 目录与文件区分处理:
- 目录的读权限对应能否遍历内容,通过创建目录迭代器验证;
- 目录的写权限对应能否创建/删除文件,通过临时文件创建验证。
- 无副作用设计:临时文件创建后立即删除,不会留下残留;文件写检查用追加模式,避免修改原有文件内容。
- 跨平台兼容:基于C++17标准库实现,同时支持Unix和Windows系统。
内容的提问来源于stack exchange,提问作者Fede2424
相关产品推荐
相关产品推荐

