随着 C++17 的发布,std::filesystem 成为 C++ 标准库的一部分,它提供了一套统一且跨平台的文件系统操作接口。相比之前常见的 POSIX API 或 Boost.Filesystem,std::filesystem 在语义上更贴近语言本身,错误处理更加安全,并且与现代 C++ 的异常安全、移动语义完美融合。
1. 为什么要使用 std::filesystem
- 跨平台:同一段代码即可在 Windows、Linux、macOS 等操作系统上编译运行,无需平台特定的预处理宏。
- 异常安全:大部分函数会抛出
std::filesystem::filesystem_error,可以通过捕获异常实现更稳健的错误处理。 - 更简洁的 API:使用
path对象代替裸字符串,支持链式操作与格式化输出。 - 性能优势:在多数实现中,std::filesystem 采用了系统级别的高效调用(如
GetFileAttributesExW、statx等),而不是包装旧的 POSIX 代码。
2. 核心概念
| 名称 | 作用 |
|---|---|
std::filesystem::path |
表示文件路径,支持拼接、查询文件名、后缀等 |
std::filesystem::directory_iterator |
逐个遍历目录项 |
std::filesystem::recursive_directory_iterator |
递归遍历子目录 |
std::filesystem::copy_options |
指定复制/移动行为(如 overwrite_existing、recursive) |
std::filesystem::file_status |
文件状态信息(大小、修改时间、权限等) |
3. 常见操作示例
3.1 创建、删除和移动文件/目录
#include <filesystem>
namespace fs = std::filesystem;
int main() {
fs::path dir = "output";
fs::create_directories(dir); // 递归创建
fs::path file = dir / "example.txt";
std::ofstream(file) << "Hello, filesystem!"; // 写文件
fs::path backup = dir / "backup";
fs::create_directories(backup);
fs::copy(file, backup / file.filename(),
fs::copy_options::overwrite_existing);
fs::remove(file); // 删除文件
fs::remove_all(backup); // 递归删除目录
}
3.2 递归遍历目录并筛选文件
for (const auto& entry : fs::recursive_directory_iterator("src")) {
if (entry.is_regular_file() && entry.path().extension() == ".cpp") {
std::cout << "Found C++ source: " << entry.path() << '\n';
}
}
3.3 检查文件属性
fs::path p = "data.bin";
if (fs::exists(p) && fs::is_regular_file(p)) {
std::cout << "Size: " << fs::file_size(p) << " bytes\n";
std::cout << "Last write: " << std::chrono::system_clock::to_time_t(
fs::last_write_time(p).time_since_epoch()) << '\n';
}
3.4 错误处理
try {
fs::create_directory("existing_dir");
} catch (const fs::filesystem_error& e) {
std::cerr << "Error: " << e.what() << '\n';
// 可以根据 e.code() 判断错误码
}
4. 与 Boost.Filesystem 的比较
| 维度 | std::filesystem | Boost.Filesystem |
|---|---|---|
| 标准化 | C++17 之后已标准化 | 仍是第三方库 |
| 依赖 | 无外部依赖 | 需要 Boost 依赖 |
| 头文件 | ` | |
|` |
||
| 异常 | filesystem_error |
boost::filesystem::filesystem_error |
| 未来 | 与编译器实现紧密 | 仍保持兼容性,但发展受限 |
5. 实践建议
- 避免裸字符串:始终使用
fs::path对象进行路径操作。 - 错误码模式:在性能敏感场景,使用
std::error_code而不是异常,避免异常开销。 - 跨平台测试:即使只在 Windows 上开发,也建议在 Linux / macOS 上编译运行一次,验证路径分隔符、权限等差异。
- 保持代码简洁:链式调用
path的成员函数,能让代码更易读。
6. 结语
std::filesystem 的加入,让 C++ 的文件系统操作不再是“低层、繁琐、易错”的痛点。无论是简单的文件复制,还是复杂的项目构建系统,都能通过标准库一次性覆盖。掌握它,能让你在 C++ 开发中更专注于业务逻辑,而不是琐碎的系统细节。