应先调用 std::filesystem::exists() 检查路径存在性,再用 is_regular_file() 和 is_directory() 判断类型;二者均在路径不存在时返回 false,无法区分“不存在”与“存在但非该类型”,且不覆盖 symlink、socket 等其他文件类型。

用 std::filesystem::is_regular_file() 和 std::filesystem::is_directory() 判断类型
标准库从 C++17 开始提供 std::filesystem,这是最直接、跨平台的方式。它不依赖系统调用细节,也不需要手动解析 stat 结构体。
注意:必须链接 -lstdc++fs(GCC)或启用 /std:c++17 + 链接 libc++fs(Clang),MSVC 通常默认支持但需确认项目设置。
-
std::filesystem::is_regular_file(path)返回true仅当路径存在且是普通文件(不含符号链接目标,除非加std::filesystem::symlink_option::follow) -
std::filesystem::is_directory(path)同理,对目录生效;若路径不存在或不是目录,返回false - 两者都要求路径存在——如果路径不存在,两个函数都返回
false,无法区分“不存在”和“存在但不是该类型”,所以务必先用std::filesystem::exists(path)检查
示例:
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
fs::path p = "/tmp/test";
if (!fs::exists(p)) {
std::cout << "path does not exist\n";
return 1;
}
if (fs::is_regular_file(p)) {
std::cout << "it's a file\n";
} else if (fs::is_directory(p)) {
std::cout << "it's a directory\n";
} else {
std::cout << "it's something else (e.g. symlink, socket, device)\n";
}
}
为什么不能只靠 is_regular_file() 或 is_directory() 单独判断
这两个函数设计为“类型断言”,不是“类型分类器”。它们只告诉你“是不是”,不告诉你“如果不是,那是什么”。
立即学习“C++免费学习笔记(深入)”;
- 符号链接(symlink)本身既不是 regular file 也不是 directory——
is_regular_file()和is_directory()对未解引用的 symlink 都返回false - 设备文件、命名管道(FIFO)、套接字等在 POSIX 下属于不同文件类型,
std::filesystem不提供对应谓词,此时两个函数也返回false - Windows 下某些重解析点(如 junction、mounted volume)行为可能与 POSIX symlink 不一致,需实测验证
所以实际逻辑应是:exists → is_regular_file → is_directory → 其他,而不是用 else if 覆盖全部可能性。
兼容 C++11/14 的替代方案:用 stat() 手动检查 st_mode
如果项目不能升级到 C++17,或者需要更细粒度控制(比如区分 block device 和 char device),就得调用底层 API。
- POSIX 系统(Linux/macOS)用
stat(),检查st_mode位掩码:S_ISREG(m)判文件,S_ISDIR(m)判目录 - Windows 用
GetFileAttributes(),返回值含FILE_ATTRIBUTE_DIRECTORY;但注意它无法可靠区分普通文件和特殊对象(如串口COM1),且对符号链接处理较弱 - 跨平台封装时,容易漏掉权限不足导致的
EPERM或EACCES错误——此时stat()失败,但路径可能存在;需检查errno而非仅看返回值
关键陷阱:stat() 默认不跟随符号链接,而 lstat() 才是查看链接本身的元数据;多数场景下你想要的是目标类型,所以该用 stat(),但得清楚自己在做什么。
常见错误:把路径字符串结尾斜杠当作目录标识
有人会写 path.back() == '/' 或 path.ends_with("/")来猜测目录,这完全不可靠。
- Windows 使用反斜杠,且路径末尾加不加
\不影响语义(C:\foo\和C:\foo可能指向同一目录) - POSIX 下,
/tmp/和/tmp是等价的,但用户输入可能随意增删斜杠;更糟的是,普通文件名也可以叫log/(虽然罕见,但合法) - 符号链接目标路径也可能带斜杠,但这不代表它真是目录
路径字符串形态和实际文件系统对象类型之间没有确定映射关系。唯一可信的来源是文件系统元数据查询,不是字符串分析。
真正麻烦的地方不在 API 选择,而在处理边界情况:权限、符号链接循环、NFS 挂载延迟响应、甚至 FAT32 这种不存 mode 位的文件系统——这时候 std::filesystem 可能抛异常或返回意外结果,得提前设好 std::filesystem::status() 的错误处理策略。


















