C++ 第三阶段 新标准库组件 - 第二节:std::filesystem(文件系统操作)

发布于:2025-06-29 ⋅ 阅读:(20) ⋅ 点赞:(0)

目录

一、std::filesystem 概述

1. 核心作用

2. 核心组件

二、std::filesystem 的基本用法

1. 路径操作(std::filesystem::path)

(1) 路径构造与拼接

(2) 路径分解

(3) 路径修改

2. 目录与文件操作

(1) 创建目录

(2) 删除目录

(3) 检查文件存在

(4) 查询文件属性

3. 目录遍历

(1) 非递归遍历

(2) 递归遍历

(3) 过滤条件

4. 文件与目录操作

(1) 复制文件或目录

(2) 移动文件或目录

三、错误处理机制

1. 异常处理

2. 基于错误码的处理

四、跨平台注意事项

1. 路径分隔符处理

示例:

2. 大小写敏感性

五、常见问题与解决方案

1. 路径拼接错误

问题:

解决方案:

2. 权限不足导致的操作失败

问题:

解决方案:

3. 递归遍历性能问题

问题:

解决方案:

六、示例代码汇总

示例 1:创建目录并检查文件大小

示例 2:递归删除目录

示例 3:遍历目录并统计文件数量

七、总结

1. std::filesystem 的核心优势

2. 适用场景

3. 最佳实践

C++从入门到入土学习导航_c++学习进程-CSDN博客


一、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++ 应用程序。


网站公告

今日签到

点亮在社区的每一天
去签到