C++17 标准库在 头文件中引入了一个强大的文件系统交互 API,极大地方便了路径拼接、文件查询、遍历以及文件属性获取等常见任务。本文将从最基础的路径操作讲起,演示如何使用 std::filesystem 完成一系列实用的文件系统任务,并简要讨论跨平台兼容性与性能注意事项。
1. 引入头文件与命名空间
#include <filesystem>
namespace fs = std::filesystem;
std::filesystem 只在 C++17 及以上可用,编译时需使用 -std=c++17 或更高的标准。
2. 路径类型与基本操作
std::filesystem::path 是一种轻量级对象,用来表示文件系统路径。它支持各种构造与操作:
fs::path p1("/usr"); // 绝对路径
fs::path p2("Documents/report.txt"); // 相对路径
fs::path p3 = p1 / p2; // 连接路径
operator/ 用于拼接子路径,内部会根据操作系统自动插入分隔符。
- 查询路径信息
std::cout << "Path: " << p3 << '\n'; std::cout << "Filename: " << p3.filename() << '\n'; // report.txt std::cout << "Extension: " << p3.extension() << '\n'; // .txt - 绝对化与相对化
fs::path abs = fs::absolute(p3); // 把相对路径变成绝对路径 fs::path rel = fs::relative(abs, "/usr"); // 从指定根生成相对路径
3. 文件与目录查询
3.1 目录遍历
使用 fs::directory_iterator(非递归)或 fs::recursive_directory_iterator(递归)遍历目录:
for (const auto& entry : fs::directory_iterator("/usr/bin")) {
std::cout << entry.path() << '\n';
}
3.2 检查文件/目录状态
fs::path file = "/etc/passwd";
if (fs::exists(file) && fs::is_regular_file(file)) {
std::cout << file << " exists and is a regular file.\n";
}
fs::status()获取文件状态信息(如大小、权限)。fs::last_write_time()读取最后修改时间。
4. 文件操作
4.1 复制、移动与删除
fs::copy_file(src, dst, fs::copy_options::overwrite_existing);
fs::rename(src, dst); // 移动或重命名
fs::remove(file); // 删除文件
fs::remove_all(dir); // 删除目录及其子文件
4.2 创建目录
fs::create_directory("/tmp/newdir");
fs::create_directories("/tmp/a/b/c"); // 自动创建多级目录
5. 示例:统计项目根目录下的所有源文件大小
fs::path root = "/home/user/project";
uintmax_t total_size = 0;
for (const auto& entry : fs::recursive_directory_iterator(root)) {
if (entry.is_regular_file() && entry.path().extension() == ".cpp") {
total_size += entry.file_size();
}
}
std::cout << "Total .cpp size: " << total_size << " bytes\n";
6. 跨平台注意事项
- 路径分隔符:
fs::path会根据平台自动使用/(Linux/Unix/macOS)或\\(Windows)。但在字符串常量中仍建议使用/,因为std::filesystem会自动转换。 - 大写与小写敏感:Windows 文件系统不区分大小写,而 Linux 是区分的。编写代码时保持一致性,避免因大小写导致的不可预料错误。
- 编码问题:Windows 的
std::filesystem::path默认使用 UTF-16(wchar_t),而 Linux 使用 UTF-8(char)。若在跨平台项目中需要统一编码,可使用fs::path::string()或wstring()进行转换。
7. 性能提示
- 使用
is_regular_file()而非exists()+is_regular_file():后者会导致两次系统调用,前者一次即可完成。 - 遍历目录时可使用
std::filesystem::directory_options::skip_permission_denied:忽略无权限目录,避免抛异常。 - 避免频繁的磁盘 I/O:若要批量操作文件,先收集路径再一次性执行即可。
8. 结语
C++17 的 std::filesystem 为文件系统交互提供了统一、类型安全且跨平台的 API。掌握基本路径操作、目录遍历与文件管理后,你可以轻松实现复杂的文件系统工具。未来在 C++20 及更高版本中,std::filesystem 将得到进一步的性能优化与新特性扩展,值得持续关注。祝你在项目中玩得开心,文件管理事半功倍!