随着 C++17 的正式发布,STL 中引入了 std::filesystem 库,彻底改变了我们在 C++ 程序中处理文件和目录的方式。传统上,开发者往往需要依赖平台特定的 API(如 Windows API 的 Win32 或 POSIX 的 ),或使用第三方库(Boost.FileSystem、libuv 等)来完成文件路径拼接、目录遍历、文件拷贝等操作。std::filesystem 的出现,为所有符合标准的编译器提供了统一、跨平台、类型安全的接口,极大地方便了文件系统编程。
1. 核心概念
1.1 path
std::filesystem::path 是对文件路径的抽象,内部采用 std::string 或 std::wstring 存储,提供了丰富的操作接口,例如:
std::filesystem::path p = "/usr/local/bin";
p /= "cpp";
p += ".exe";
使用 operator/= 可以自动处理路径分隔符,无论是 Windows 的 \ 还是 POSIX 的 /。
1.2 directory_iterator / recursive_directory_iterator
directory_iterator用于一次性遍历指定目录下的文件与子目录。recursive_directory_iterator递归遍历整个目录树。
示例:
for (const auto& entry : std::filesystem::directory_iterator("/tmp"))
std::cout << entry.path() << '\n';
1.3 file_status 与 file_type
使用 status() 或 symlink_status() 可以获取文件的属性,如大小、类型、权限等。
auto ftype = std::filesystem::file_type::regular_file;
if (std::filesystem::status(p).type() == ftype) { /* ... */ }
2. 常见操作示例
2.1 检查文件是否存在
if (std::filesystem::exists("data.txt")) {
std::cout << "文件存在\n";
}
2.2 获取文件大小
std::uintmax_t sz = std::filesystem::file_size("data.txt");
std::cout << "大小: " << sz << " 字节\n";
2.3 复制、移动、删除文件
std::filesystem::copy_file(src, dst, std::filesystem::copy_options::overwrite_existing);
std::filesystem::rename(src, dst); // 移动
std::filesystem::remove(path); // 删除单文件
std::filesystem::remove_all(dir); // 删除目录及其所有内容
2.4 创建和删除目录
std::filesystem::create_directories("/tmp/foo/bar/baz"); // 多级目录
std::filesystem::remove_all("/tmp/foo"); // 删除整棵树
3. 线程安全与异常处理
std::filesystem 所有操作都是线程安全的,但在并发读写同一文件时需要自行同步。异常方面,所有函数都可能抛出 std::filesystem::filesystem_error,可通过捕获该异常获取详细错误信息:
try {
std::filesystem::remove("nonexistent.txt");
} catch (const std::filesystem::filesystem_error& e) {
std::cerr << e.what() << '\n';
}
4. 性能注意
- 延迟加载:
directory_iterator在迭代时才查询文件系统,避免一次性读取大量目录。 - 缓存:
status()可能触发磁盘访问,频繁调用会导致性能下降,建议使用symlink_status()或自行缓存结果。 - IO 调度:对大文件读写时,使用
std::ofstream/std::ifstream配合std::filesystem::copy_file更快。
5. 与 Boost.FileSystem 的对比
Boost.FileSystem 是 std::filesystem 的前身,功能几乎相同,但存在以下差异:
| 维度 | std::filesystem | Boost.FileSystem |
|---|---|---|
| 标准化 | 是 C++17 标准 | 非标准 |
| 头文件 | ||
| 类型安全 | 高(使用 path 类型) | 低(多使用字符串) |
| 依赖 | 无 | Boost 依赖 |
| 线程安全 | 是 | 是(但实现细节不同) |
若项目已迁移到 C++17 或更高版本,建议直接使用 std::filesystem,除非需要保持向后兼容。
6. 小结
std::filesystem 为 C++ 提供了完整、跨平台、类型安全的文件系统接口,极大简化了文件操作代码。熟练掌握其核心类和函数后,许多日常任务(路径拼接、目录遍历、文件复制等)将变得毫不费力。未来的 C++ 标准会继续扩展该库,例如在 C++20 中增加了 temp_directory_path()、current_path() 的改进,以及在 C++23 中对异常类型和错误码的进一步完善。掌握 std::filesystem 是现代 C++ 开发者不可或缺的技能。