
用 std::filesystem::exists 判断路径是不是目录(C++17)
最直接的方式是先确认路径存在,再确认它是目录而非文件。C++17 引入的 std::filesystem 是目前标准、跨平台的首选,不用依赖 Boost 或系统 API。
常见错误是只调用 exists() 就认为“目录存在”,但该函数对文件和目录都返回 true —— 它只回答“这个路径有没有”,不区分类型。
- 必须配合
is_directory()一起用:if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { /* 是有效目录 */ } - 如果
path是相对路径(比如"./data"),行为依赖当前工作目录,容易在不同环境出错;建议用绝对路径或提前 resolve:std::filesystem::absolute(path) - 某些老旧编译器(如 GCC 8.1 之前)默认不启用
std::filesystem,需加编译选项:-lstdc++fs(GCC)或/std:c++17+ 链接Shlwapi.lib(MSVC)
Windows 下用 GetFileAttributesW 检查目录(兼容 C++11 及更早)
当项目不能升级到 C++17,又必须支持 Windows,GetFileAttributesW 是轻量且可靠的选择。它比 CreateFile 开销小,也比 FindFirstFile 简洁。
关键点在于:返回值不是布尔,而是位掩码,且需检查 INVALID_FILE_ATTRIBUTES 错误态。
立即学习“C++免费学习笔记(深入)”;
- 必须用宽字符路径(
L"..."),传入char*会返回INVALID_FILE_ATTRIBUTES,看起来像“目录不存在” - 判断逻辑是:
(attrs & FILE_ATTRIBUTE_DIRECTORY) != 0,但前提是attrs != INVALID_FILE_ATTRIBUTES - 它对符号链接(symlink)默认不解析,若需跟随链接,得先用
GetFinalPathNameByHandle,否则可能误判
Linux/macOS 下用 stat() 判断目录(POSIX 兼容方案)
stat() 是 Unix-like 系统最底层也最稳妥的方式,不依赖 C++ 标准库版本,但要注意 struct 成员名和宏定义的大小写敏感性。
典型错误是把 S_ISDIR(st.st_mode) 写成 S_ISDIR(st.st_mode) == 1 —— 宏本身已展开为表达式,多加 == 1 在某些旧 libc 下可能意外为真(比如宏返回非 0 整数),导致逻辑混乱。
- 必须包含
<sys></sys>和<unistd.h></unistd.h>,否则stat()声明缺失,编译可能通过但运行时崩溃 -
stat()对软链接会解引用;若要检查链接本身是否为目录(而非目标),改用lstat() - 路径含中文或特殊字符时,确保程序 locale 设置正确,否则
stat()可能返回ENOENT(即使路径真实存在)
跨平台封装时最容易被忽略的权限与竞态问题
无论用哪种方法,只要检查完“目录存在”就立刻去读写,大概率踩坑。操作系统层面没有原子性保证 —— 检查和后续操作之间,目录可能被删、重命名、或权限被改。
这不是设计缺陷,而是所有文件系统共有的现实约束。实际工程中,应把“检查”当作可选预检,核心逻辑仍需靠操作失败后的 errno 处理(比如 open() 失败时看是不是 ENOENT 或 EACCES)。
- 不要写
if (is_dir()) { open_dir(); },而应直接opendir()并检查返回值 - 某些容器环境(如 rootless Podman)或网络文件系统(NFSv3)下,
exists()可能缓存过期,返回假阳性 - Android NDK r21+ 起
std::filesystem才可用;旧版本只能走stat()或 JNI 调用java.io.File.isDirectory()










