c++17起应优先使用std::filesystem::is_regular_file()和is_directory()判断文件类型,二者均要求路径存在且可访问,否则抛异常;需先用exists()检查存在性,再分情况处理文件、目录及其他类型。

用 std::filesystem::is_regular_file() 和 std::filesystem::is_directory() 判断类型
标准库从 C++17 开始提供 std::filesystem,这是最直接、跨平台的方案。它不依赖系统 API,也不需要手动处理符号链接歧义(默认会解引用)。
关键点:两个函数都要求路径存在且可访问,否则抛出 std::filesystem::filesystem_error。务必捕获异常或先用 exists() 检查。
-
is_regular_file(path)返回true仅当是普通文件(不含目录、socket、设备节点等) -
is_directory(path)对目录返回true,对符号链接指向的目录也返回true(除非加std::filesystem::symlink_option::no_follow) - 若路径不存在,两者都返回
false—— 所以不能单靠false推断“是另一个类型”,必须结合exists()
#include <filesystem>
namespace fs = std::filesystem;
fs::path p = "/tmp/test";
if (!fs::exists(p)) {
// 路径不存在
} else if (fs::is_regular_file(p)) {
// 是文件
} else if (fs::is_directory(p)) {
// 是目录
} else {
// 可能是符号链接、套接字、FIFO 等其他类型
}</filesystem>
Windows 下用 GetFileAttributes() 需注意 FILE_ATTRIBUTE_DIRECTORY
如果项目不能用 C++17,或需精确控制符号链接行为(比如想区分“链接本身”和“链接目标”),Windows 原生 API 仍常用。但别只看返回值是否为 -1 —— 大部分错误(如权限不足、路径过长)也会返回 -1,需用 GetLastError() 进一步判断。
-
GetFileAttributes(L"some_path") & FILE_ATTRIBUTE_DIRECTORY为真,表示是目录(含符号链接指向的目录) - 若想跳过符号链接,得先用
GetFileAttributesEx()配合GET_FILEEX_INFO_LEVELS::GetFileExInfoStandard,再检查dwFileAttributes字段 - 返回
INVALID_FILE_ATTRIBUTES不等于“不是目录”,可能是路径不存在、无访问权、或是重解析点(如挂载点)未被识别
Linux/macOS 下用 stat() 看 st_mode 位标志
stat() 是 POSIX 标准方式,比 access() 更可靠,因为它不触发权限检查副作用,且能一次获取全部元数据。
- 成功时检查
sb.st_mode & S_IFMT的值:S_IFREG是普通文件,S_IFDIR是目录 - 别直接用
S_ISREG(sb.st_mode)或S_ISDIR(sb.st_mode)宏——它们内部已做掩码,更安全 - 若
stat()返回 -1,errno是关键:ENOENT是不存在,EACCES是没权限读取父目录(注意:即使目标存在,也可能因父目录不可执行而失败) - 对符号链接,默认
stat()获取的是目标属性;要用lstat()获取链接自身属性
容易忽略的边界情况:符号链接、挂载点、权限与空路径
很多 bug 出在假设“非文件即目录”。实际还有不少中间态:
- 符号链接可能指向不存在的路径,此时
is_regular_file()和is_directory()都返回false,但is_symlink()为true - 某些文件系统挂载点(如 NFS、/proc)下,
stat()可能成功但st_mode不符合常规分类,std::filesystem在这些场景下行为取决于底层实现 - 传入空字符串或只含空白符的
fs::path,构造时不会报错,但后续操作会抛异常 —— 建议提前用p.empty()或p.generic_string().find_first_not_of(" \t\n\r") == std::string::npos过滤 - 权限问题在容器或沙盒环境里尤其隐蔽:路径存在,但父目录不可遍历(
noexec或nodev挂载选项),导致stat()或is_*失败
真正健壮的判断逻辑,永远要先处理“不存在”和“不可访问”,再分类型,最后考虑“其他类型”的 fallback 分支。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











