最可靠方式是先调用std::filesystem::exists(path)确认路径存在,再用std::filesystem::is_regular_file()和std::filesystem::is_directory()判断类型;二者对不存在路径均返回false,且默认不追踪符号链接,需显式指定symlink_option::follow才能检查目标类型。

用 std::filesystem::is_regular_file 和 std::filesystem::is_directory 判断最可靠
C++17 起,std::filesystem 是标准且跨平台的方案。它不依赖系统调用细节,也不需要手动处理 stat 或 GetFileAttributes 的返回值差异。
关键点是:必须先确认路径存在,否则两个函数都返回 false——这不是错误,而是“不存在即非文件也非目录”。
- 先调用
std::filesystem::exists(path),再判断类型 -
is_regular_file()对符号链接默认不追踪(即判断链接本身是否为普通文件),如需追踪目标,传入std::filesystem::symlink_option::follow -
is_directory()同样对符号链接默认不追踪;若链接指向目录但本身是链接,直接调用会返回false - Windows 下长路径(>260 字符)需确保程序启用 Unicode 支持(如编译时定义
UNICODE,且路径为std::wstring或 UTF-8 编码并正确转换)
#include <filesystem>
namespace fs = std::filesystem;
fs::path p = "data/config.json";
if (fs::exists(p)) {
if (fs::is_regular_file(p)) {
// 是普通文件
} else if (fs::is_directory(p)) {
// 是目录
}
}
为什么不用 stat() 或 GetFileAttributes()?
裸系统 API 问题多:Linux 的 stat() 需检查 st_mode 中的宏(S_ISREG / S_ISDIR),但若路径不存在或权限不足,stat() 返回 -1,errno 值易被忽略;Windows 的 GetFileAttributes() 返回 INVALID_FILE_ATTRIBUTES 时,还需额外调用 GetLastError() 区分“不存在”和“拒绝访问”,逻辑容易漏分支。
-
stat()在 NFS 或某些挂载点上可能阻塞或返回过时缓存结果 -
GetFileAttributes()对末尾带反斜杠的路径(如"C:\temp\")行为不一致:有的版本强制视为目录,有的则失败 - 两者都不处理 Unicode 路径在窄字符接口下的截断风险(尤其 Windows 上用
char*调用)
常见误判场景和应对
用户常以为“能打开就是文件”或“有子项就是目录”,但这不可靠:设备文件(如 /dev/null)可读但不是 regular file;空目录当然没子项;而某些 FUSE 文件系统甚至让普通文件表现出目录迭代行为。
- 不要用
fopen()成功与否判断文件类型——设备文件、命名管道也能fopen成功 - 不要用
opendir()是否成功判断目录——某些只读挂载点下opendir失败,但路径确实是目录 - 符号链接必须显式处理:默认情况下
is_regular_file()和is_directory()都作用于链接自身;要判断目标类型,统一加fs::symlink_option::follow - 注意路径字符串结尾的斜杠:
"dir/"和"dir"在大多数文件系统中等价,但某些容器化环境或网络文件系统可能敏感
兼容 C++14 或更早版本怎么办?
没有 std::filesystem 时,只能按平台分支处理,且必须接受局限性:无法完全规避竞态条件(check-then-act 问题),也不能优雅处理符号链接策略。
立即学习“C++免费学习笔记(深入)”;
- Linux/macOS:用
stat()+S_ISREG()/S_ISDIR(),但务必检查stat()返回值是否为 0 - Windows:用
GetFileAttributesW()(宽字符版),检查返回值是否包含FILE_ATTRIBUTE_DIRECTORY,同时排除FILE_ATTRIBUTE_REPARSE_POINT(需额外判断是否为符号链接) - 第三方库如 Boost.Filesystem 可作为过渡,但引入依赖需权衡;它的接口与
std::filesystem高度相似,迁移成本低
真正麻烦的不是写几行判断代码,而是后续操作是否与类型匹配——比如对目录调用 fopen 必然失败,但错误信息往往只说 “No such file or directory”,掩盖了类型误用的本质。


















