目录
1. 路径操作(std::filesystem::path)
一、std::filesystem
概述
1. 核心作用
std::filesystem
是 C++17 引入的标准化文件系统操作库,基于 Boost.Filesystem 的功能实现。它解决了以下问题:
- 跨平台兼容性:统一处理 Windows(使用
\
分隔符)和 POSIX(使用/
分隔符)系统的路径差异。 - 类型安全:通过
std::filesystem::path
类封装路径操作,避免手动拼接字符串导致的错误。 - 简化复杂操作:提供目录遍历、文件属性查询、路径分解等高阶功能。
2. 核心组件
类/函数 | 功能描述 |
---|---|
std::filesystem::path |
表示文件路径,支持路径拼接、分解、检查等操作。 |
std::filesystem::directory_iterator |
遍历目录中的条目。 |
std::filesystem::recursive_directory_iterator |
递归遍历目录及其子目录。 |
std::filesystem::create_directory |
创建单个目录。 |
std::filesystem::remove |
删除文件或空目录。 |
std::filesystem::exists |
检查文件或目录是否存在。 |
std::filesystem::file_size |
查询文件大小。 |
std::filesystem::copy |
复制文件或目录。 |
二、std::filesystem
的基本用法
1. 路径操作(std::filesystem::path
)
(1) 路径构造与拼接
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
fs::path p1 = "C:/Users/Example"; // Windows 路径
fs::path p2 = "/home/user/documents"; // Linux 路径
fs::path p3 = p1 / "data" / "file.txt"; // 自动适配系统分隔符
std::cout << "Path: " << p3 << std::endl;
std::cout << "Native path: " << p3.native() << std::endl; // 显示系统原生格式
}
(2) 路径分解
fs::path p = "C:/Users/Example/data/file.txt";
std::cout << "Root name: " << p.root_name() << std::endl; // C:
std::cout << "Root path: " << p.root_path() << std::endl; // C:/
std::cout << "Relative path: " << p.relative_path() << std::endl; // Users/Example/data/file.txt
std::cout << "Parent path: " << p.parent_path() << std::endl; // C:/Users/Example/data
std::cout << "Filename: " << p.filename() << std::endl; // file.txt
std::cout << "Stem: " << p.stem() << std::endl; // file
std::cout << "Extension: " << p.extension() << std::endl; // .txt
(3) 路径修改
fs::path p = "C:/Users/Example/data/file.txt";
p.remove_filename(); // 移除文件名部分 → C:/Users/Example/data/
p.replace_extension(".bak"); // 修改后缀 → C:/Users/Example/data/file.bak
p.make_preferred(); // 转换为系统首选分隔符 → C:\Users\Example\data\file.bak (Windows)
2. 目录与文件操作
(1) 创建目录
fs::create_directory("new_dir"); // 创建单级目录(父目录必须存在)
fs::create_directories("nested_dir/sub_dir"); // 递归创建多级目录
(2) 删除目录
fs::remove("empty_dir"); // 删除空目录
fs::remove_all("dir_with_files"); // 递归删除目录及内容
(3) 检查文件存在
if (fs::exists("example.txt")) {
std::cout << "File exists!" << std::endl;
} else {
std::cout << "File not found." << std::endl;
}
(4) 查询文件属性
if (fs::exists("example.txt")) {
std::cout << "File size: " << fs::file_size("example.txt") << " bytes" << std::endl;
std::cout << "Last modified time: " << fs::last_write_time("example.txt") << std::endl;
}
3. 目录遍历
(1) 非递归遍历
for (const auto& entry : fs::directory_iterator("C:/")) {
std::cout << "Entry: " << entry.path() << std::endl;
}
(2) 递归遍历
for (const auto& entry : fs::recursive_directory_iterator(".")) {
std::cout << "Recursive entry: " << entry.path() << std::endl;
}
(3) 过滤条件
for (const auto& entry : fs::directory_iterator(".")) {
if (entry.is_regular_file() && entry.path().extension() == ".cpp") {
std::cout << "C++ source file: " << entry.path() << std::endl;
}
}
4. 文件与目录操作
(1) 复制文件或目录
fs::copy("source.txt", "destination.txt"); // 复制文件
fs::copy("source_dir", "destination_dir", fs::copy_options::recursive); // 递归复制目录
(2) 移动文件或目录
fs::rename("old_name.txt", "new_name.txt"); // 重命名文件
fs::rename("old_dir", "new_dir"); // 重命名目录
三、错误处理机制
1. 异常处理
默认情况下,std::filesystem
会抛出 std::filesystem::filesystem_error
异常:
try {
fs::remove("nonexistent_file");
} catch (const fs::filesystem_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
2. 基于错误码的处理
通过传递 std::error_code
参数,避免异常抛出:
std::error_code ec;
fs::remove("nonexistent_file", ec);
if (ec) {
std::cerr << "Error: " << ec.message() << std::endl;
}
四、跨平台注意事项
1. 路径分隔符处理
- Windows:使用
\
作为路径分隔符,但std::filesystem::path
会自动将/
转换为\
。 - POSIX:使用
/
作为路径分隔符,std::filesystem::path
会保持原样。
示例:
fs::path p1 = "C:/Users/Example"; // Windows 下自动转换为 C:\Users\Example
fs::path p2 = "/home/user/documents"; // Linux 下保持不变
2. 大小写敏感性
- Windows:路径大小写不敏感。
- Linux/macOS:路径大小写敏感。
五、常见问题与解决方案
1. 路径拼接错误
问题:
手动拼接路径可能导致分隔符错误(如 C:/Users/Example\file.txt
)。
解决方案:
使用 std::filesystem::path
的 /
操作符自动适配分隔符。
2. 权限不足导致的操作失败
问题:
尝试删除或修改受保护的文件或目录时抛出异常。
解决方案:
- 使用
try-catch
捕获异常或检查错误码。 - 在操作系统中提升权限后再执行操作。
3. 递归遍历性能问题
问题:
recursive_directory_iterator
可能因大量文件导致性能下降。
解决方案:
- 添加过滤条件减少遍历范围。
- 在非实时场景中异步处理。
六、示例代码汇总
示例 1:创建目录并检查文件大小
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
fs::path dir = "example_dir";
if (!fs::exists(dir)) {
fs::create_directory(dir);
std::cout << "Directory created: " << dir << std::endl;
}
fs::path file = dir / "example.txt";
std::ofstream(file) << "Hello, filesystem!"; // 写入内容
if (fs::exists(file)) {
std::cout << "File size: " << fs::file_size(file) << " bytes" << std::endl;
}
return 0;
}
示例 2:递归删除目录
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
fs::path dir = "test_dir";
if (fs::exists(dir)) {
fs::remove_all(dir);
std::cout << "Directory removed: " << dir << std::endl;
} else {
std::cout << "Directory does not exist." << std::endl;
}
return 0;
}
示例 3:遍历目录并统计文件数量
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
int file_count = 0;
for (const auto& entry : fs::recursive_directory_iterator(".")) {
if (entry.is_regular_file()) {
++file_count;
}
}
std::cout << "Total files: " << file_count << std::endl;
return 0;
}
七、总结
1. std::filesystem
的核心优势
- 跨平台兼容性:统一处理不同操作系统的路径差异。
- 类型安全:通过
path
类避免手动拼接路径错误。 - 简化复杂操作:提供高阶 API(如目录遍历、属性查询)。
2. 适用场景
- 文件管理工具:如资源管理器、备份工具。
- 自动化脚本:批量处理文件或目录。
- 跨平台应用:需要兼容 Windows 和 Linux 的项目。
3. 最佳实践
- 优先使用
std::filesystem::path
:替代字符串拼接。 - 结合异常处理与错误码:根据需求选择错误处理方式。
- 注意递归操作的性能:添加过滤条件或异步处理。
通过掌握 std::filesystem
,开发者可以高效、安全地处理文件系统操作,构建跨平台且健壮的 C++ 应用程序。