在 C++17 标准中,std::filesystem 库为文件和目录的操作提供了统一且安全的接口。它解决了以往在 Windows 与 POSIX 系统间切换时路径分隔符、字符编码等兼容性问题,同时也避免了大量手写字符串拼接导致的错误。下面我们从基础使用、常见操作和注意事项三部分进行系统介绍。
1. 基础概念
#include <filesystem>
namespace fs = std::filesystem;
- 路径对象:
fs::path用来表示文件或目录的路径。它可以直接用字符串构造,内部会根据平台自动使用正确的分隔符。 - 文件系统对象:
fs::file_status、fs::directory_entry等用于存取文件属性。 - 异常:默认情况下,所有函数会抛出
std::filesystem::filesystem_error,可以通过捕获来处理错误。
2. 常见路径操作
| 操作 | 代码示例 | 说明 |
|---|---|---|
| 拼接 | fs::path p = "/usr"; p /= "local"; p /= "bin"; |
operator/= 自动插入分隔符 |
| 规范化 | auto norm = fs::canonical(p); |
解析符号链接、相对路径,返回绝对路径 |
| 获取父目录 | auto parent = p.parent_path(); |
只返回上一层路径 |
| 迭代目录 | for (const auto &entry : fs::directory_iterator(dir)) {} |
遍历目录下所有文件 |
| 检查存在 | if (fs::exists(p)) {} |
判断文件或目录是否存在 |
| 创建目录 | fs::create_directories("a/b/c"); |
同时创建多级目录 |
| 复制、移动 | fs::copy(src, dst); fs::rename(src, dst); |
支持多种复制选项、错误处理 |
3. 处理文件大小和时间戳
auto size = fs::file_size(p); // 文件大小,单位字节
auto mod_time = fs::last_write_time(p); // 最后修改时间,返回的是系统时间点
若需要将 mod_time 转换为 std::chrono::system_clock 时间,可以使用 chrono::file_clock::to_sys。
4. 处理权限
fs::permissions(p,
fs::perms::owner_read | fs::perms::owner_write,
fs::perm_options::replace);
permissions 允许精确控制文件或目录的读写执行权限,兼容 Windows 和 POSIX 权限模型。
5. 与旧代码的互通
std::string oldPath = "C:\\Windows\\System32";
fs::path newPath = oldPath; // 自动转换
如果你已经有大量使用 std::string 的路径处理代码,只需一次性替换为 fs::path,后续即可享受类型安全。
6. 性能与注意事项
- 性能:
std::filesystem的实现通常使用系统 API,开销与手写调用相当,除非在极端循环中,才会有微小差别。 - 异常:默认抛出异常;若想使用错误码,使用带
std::error_code &ec的重载。 - 跨平台:Windows 与 POSIX 的路径符号不同,但
fs::path自动处理;注意符号链接在 Windows 需要管理员权限。
7. 实战示例:递归删除临时文件夹
void removeTemp(const fs::path& root) {
std::error_code ec;
for (auto &entry : fs::directory_iterator(root, ec)) {
if (ec) { std::cerr << "Dir iter error: " << ec.message(); continue; }
if (entry.is_directory(ec)) {
removeTemp(entry.path());
} else if (entry.is_regular_file(ec)) {
fs::remove(entry.path(), ec);
if (ec) std::cerr << "Remove file error: " << ec.message();
}
}
fs::remove(root, ec); // 删除空目录
}
该函数使用错误码避免异常,递归删除目录中的所有文件与子目录,最终删除根目录。
8. 小结
std::filesystem 在 C++17 之后成为了标准库不可缺少的一部分,它为路径、文件系统操作提供了:
- 统一接口:跨平台,避免手写分隔符
- 类型安全:使用
fs::path而非裸字符串 - 丰富功能:文件复制、权限、时间戳、符号链接等全覆盖
- 易用性:异常机制与错误码兼容,开发者可根据需求选择
在新项目中尽量使用 std::filesystem,旧项目也可以逐步迁移,以获得更安全、可维护、跨平台的文件系统操作。祝编码愉快!