在读取配置文件或处理用户数据之前,我们通常需要先确认磁盘上的目标文件到底存不存在,避免直接打开不存在的路径导致读取失败。
在 <filesystem> 标准库中,fs::path 只负责在内存里保存路径名称。如果想要去磁盘上检查某个路径是否存在、区分它是普通文件还是文件夹,我们可以调用 fs::exists()、fs::is_regular_file() 和 fs::is_directory() 等函数。
使用 exists() 判断路径是否存在
在 C++ 中,fs::exists() 函数的作用非常直观,就是去磁盘上检查指定路径当前是否存在。就像我们在纸上写了一个房间地址,并不代表那间房子真实存在,只有调用 fs::exists() 才会真正去文件系统里查一查,如下图所示。

语法:
fs::exists(path)说明:
这里的 fs 是命名空间 std::filesystem 的常用别名。fs::exists() 接收一个 fs::path 对象或路径字符串作为参数,并返回一个 bool 值:如果该路径在磁盘上存在,返回 true;如果不存在,则返回 false。
示例 1:判断路径是否存在
#include <filesystem>
#include <fstream>
#include <iostream>
namespace fs = std::filesystem;
int main() {
// 先创建一个测试文件 lvye.txt
std::ofstream outFile("lvye.txt");
outFile << "lvyenet\n";
outFile.close();
fs::path p1 = "lvye.txt";
fs::path p2 = "missing.txt";
bool e1 = fs::exists(p1);
bool e2 = fs::exists(p2);
std::cout << std::boolalpha; // 让 bool 值显示为 true 或 false
std::cout << "lvye.txt 是否存在:" << e1 << '\n';
std::cout << "missing.txt 是否存在:" << e2 << '\n';
return 0;
}运行结果如下。
lvye.txt 是否存在:true
missing.txt 是否存在:false分析:
在这个例子中,我们先创建了测试文件 "lvye.txt",所以调用 fs::exists(p1) 检查时返回 true。而当前目录下并没有 "missing.txt",因此 fs::exists(p2) 返回 false。
另外,代码中的 std::boolalpha 是输出格式控制符,作用是让后面的 bool 值直接打印为 true 或 false,而不是默认的数字 1 或 0。
判断文件类型与获取大小
需要特别注意的是,fs::exists() 返回 true 只能说明 “这个路径上有东西存在”,但它不会区分普通文件与文件夹。比如磁盘上刚好有一个名叫 config 的文件夹,fs::exists("config") 也会返回 true,这时直接拿文件流当文本去读就会失败。
因此在实际开发中,我们经常使用 fs::is_regular_file() 判断目标是不是普通文件,使用 fs::is_directory() 判断是不是目录,确认是普通文件后再调用 fs::file_size() 查看字节数。这几个常用函数的对比如下表所示。
| 函数 | 作用说明 | 返回值说明 |
|---|---|---|
| fs::exists(path) | 判断路径是否存在 | 文件或目录存在时均返回 true |
| fs::is_regular_file(path) | 判断是否为普通文件 | 路径存在且为普通文件时返回 true |
| fs::is_directory(path) | 判断是否为目录 | 路径存在且为目录时返回 true |
| fs::file_size(path) | 获取普通文件的大小 | 返回字节数,类型为 std::uintmax_t |
语法:
fs::is_regular_file(path)
fs::is_directory(path)
fs::file_size(path)说明:
其中,regular 是英文 “常规、普通” 的意思,用来区分文件夹或系统设备等特殊条目。当我们调用 fs::is_regular_file(path) 或 fs::is_directory(path) 时,如果路径本身不存在,它们会直接返回 false 而不会报错。
也就是说,如果我们只需要确认 “它是不是已存在的普通文件”,直接调用 fs::is_regular_file(path) 一句代码就够了,不需要在前面多写一次 fs::exists(path)。
至于 fs::file_size(path) 返回的 std::uintmax_t,是 <cstdint> 头文件中定义的无符号大整数类型,专门用来表示大文件的字节大小。日常打印或比较大小时,大家直接把它当成普通的非负整数使用即可。
示例 2:判断类型与查看大小
#include <cstdint> // 提供 std::uintmax_t
#include <filesystem>
#include <fstream>
#include <iostream>
namespace fs = std::filesystem;
int main() {
// 写入 7 个字母,占 7 个字节
std::ofstream outFile("lvye.txt");
outFile << "lvyenet";
outFile.close();
fs::path file = "lvye.txt";
fs::path dir = "."; // "." 表示当前工作目录
bool isFile = fs::is_regular_file(file);
bool isDir = fs::is_directory(file);
std::uintmax_t size = fs::file_size(file);
bool cwdIsDir = fs::is_directory(dir);
std::cout << std::boolalpha;
std::cout << "lvye.txt 是普通文件:" << isFile << '\n';
std::cout << "lvye.txt 是目录:" << isDir << '\n';
std::cout << "lvye.txt 的大小:" << size << " 字节\n";
std::cout << "当前路径 . 是目录:" << cwdIsDir << '\n';
return 0;
}运行结果如下。
lvye.txt 是普通文件:true
lvye.txt 是目录:false
lvye.txt 的大小:7 字节
当前路径 . 是目录:true分析:
由于 lvye.txt 是普通文本文件,isFile 的结果为 true,isDir 的结果为 false。我们在文件里写入了 "lvyenet" 共 7 个英文字母,每个英文字母占 1 个字节,所以 fs::file_size(file) 返回的文件大小为 7。
同时,代码中的 "." 代表当前工作目录。它本身是一个文件夹,因此 fs::is_directory(dir) 返回 true。
注意 fs::file_size() 只能用来查询普通文件的大小。小伙伴们千万不要对文件夹或不存在的路径直接调用该函数,否则程序运行时会抛出异常报错。在不确定路径类型时,建议先通过 fs::is_regular_file() 确认后再查询大小。
使用 error_code 免异常检查
在前面的例子中,我们调用 fs::exists(path) 时只传入了一个路径参数,大多数情况下这样写都没问题。但如果遇到没有访问权限的系统目录或磁盘故障,单参数版本就会直接抛出异常,需要配合 try...catch 来捕获。
如果我们不希望程序抛出异常,并且想把 “路径单纯不存在” 和 “查询过程本身出错” 这两种情况区分开,可以在调用函数时额外传入第 2 个参数 std::error_code。
语法:
std::error_code ec;
fs::exists(path, ec)说明:
在使用 std::error_code 之前,我们需要先通过 #include <system_error> 引入头文件。ec 是专门用来接收错误信息的错误码对象,判断规则如下:
- 查询过程出错:程序不会抛出异常,而是把非 0 的错误编号记录到
ec中。此时if (ec)条件为true,我们可以调用ec.message()查看具体的错误描述。 - 查询过程正常:错误码保持为 0(即无错误),此时
if (ec)条件为false,接着我们再根据函数返回值是true还是false判断路径是否存在。
示例 3:结合 error_code 检查路径
#include <filesystem>
#include <iostream>
#include <system_error>
namespace fs = std::filesystem;
int main() {
fs::path path = "no_such_entry.txt";
std::error_code ec;
bool exists = fs::exists(path, ec);
if (ec) {
std::cout << "查询出错:" << ec.message() << '\n';
return 1;
}
if (exists) {
std::cout << "路径存在\n";
} else {
std::cout << "路径不存在,且查询过程未出错\n";
}
return 0;
}运行结果如下。
路径不存在,且查询过程未出错分析:
在这个例子中,虽然当前目录下并没有 "no_such_entry.txt",但操作系统顺利执行完了这次查找,中途没有遇到权限拦截或磁盘故障。因此 ec 保持无错误状态,if (ec) 判断为 false,同时返回值 exists 为 false。
这一点小伙伴们要分清楚:“文件不存在” 本身是一个正常的查询结果,并不属于系统故障。除了 fs::exists(),前面介绍的 fs::is_regular_file()、fs::is_directory() 和 fs::file_size() 也都支持在末尾传入 ec 参数。
