在 C++17 标准中,std::filesystem 库被正式纳入标准库,为文件和目录操作提供了统一、跨平台的接口。相比旧时的 POSIX API 或 Boost.Filesystem,std::filesystem 更易使用且与 C++ 语言特性深度融合。下面从概念、核心类型、常见操作、性能考虑以及实际应用案例四个方面进行系统阐述。
一、核心概念与命名空间
- 命名空间:
namespace std::filesystem,可简写为namespace fs,常用别名。 - 路径对象:
fs::path,封装文件系统路径,支持字符串、字符宽度、以及拼接、切分等操作。 - 文件/目录状态:
fs::file_status与fs::directory_entry,分别代表文件元信息与目录项。
二、主要功能模块
| 模块 | 主要函数/类型 | 说明 |
|---|---|---|
| 路径操作 | fs::path, operator/, operator/= |
路径拼接、获取扩展名、父目录等 |
| 文件系统遍历 | fs::directory_iterator, fs::recursive_directory_iterator |
迭代器式遍历,支持递归 |
| 文件属性 | fs::status, fs::symlink_status, fs::file_type, fs::permissions |
查询文件类型、权限、时间戳 |
| 文件操作 | fs::copy, fs::rename, fs::remove, fs::remove_all, fs::create_directory, fs::create_directories, fs::create_symlink |
常见文件系统操作 |
| 字符串编码 | fs::u8path, fs::u16path, fs::u32path |
处理 UTF-8/UTF-16/UTF-32 路径 |
| 错误处理 | fs::filesystem_error |
统一异常类型,包含 std::error_code |
三、典型使用案例
1. 递归遍历并打印所有文件
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
fs::path root = "./src";
try {
for (const auto& entry : fs::recursive_directory_iterator(root)) {
std::cout << entry.path() << '\n';
}
} catch (const fs::filesystem_error& e) {
std::cerr << "Error: " << e.what() << '\n';
}
}
2. 复制文件并保持权限
fs::copy(src, dst, fs::copy_options::overwrite_existing | fs::copy_options::update_existing);
3. 读取文件修改时间并格式化
auto ftime = fs::last_write_time(file);
auto sctp = std::chrono::system_clock::to_time_t(
std::chrono::file_clock::to_sys(ftime));
std::cout << std::put_time(std::localtime(&sctp), "%F %T") << '\n';
四、性能与实现细节
- 延迟异常:默认
std::filesystem在异常模式下会抛出fs::filesystem_error,但也可以通过std::error_code方式获取错误信息,避免异常开销。 - 缓存机制:在递归遍历时,
fs::directory_iterator会在每次调用++时重新读取目录条目,避免显式缓存;若对性能敏感,可自行缓存。 - 跨平台差异:Windows 上
fs::path默认使用 UTF-16(std::wstring),Linux/macOS 使用 UTF-8。使用fs::u8path可强制统一为 UTF-8。
五、实战场景
- 构建系统:在编译器或脚本中,使用
fs::recursive_directory_iterator搜索.cpp/.h,生成依赖关系。 - 日志归档:每天将日志文件复制到时间戳文件夹,使用
fs::create_directories自动创建多层目录。 - 文件同步工具:比较源与目标的
last_write_time与file_size,决定是否拷贝。
六、常见坑与最佳实践
- 不要滥用
fs::copy的overwrite_existing:若目标文件正被其他进程使用,拷贝会抛异常;可先尝试remove_all再复制。 - 符号链接注意:默认
fs::copy会复制链接本身;若想复制链接所指向的文件,使用fs::copy_options::copy_symlinks。 - 权限保持:Windows 与 POSIX 的权限模型不同,
fs::permissions仅在 POSIX 下有效;Windows 使用 ACL,需要额外处理。
七、总结
std::filesystem 的加入,使得 C++ 能够像脚本语言那样轻松处理文件系统。其 API 设计优雅,异常安全,且与现代 C++ 语言特性(如 std::error_code、std::filesystem::path)无缝集成。掌握核心类型与常用函数后,即可在项目中快速实现文件遍历、复制、删除等功能,为代码简洁性与可维护性奠定坚实基础。