跳转到内容

C++17 文件系统

来自代码酷

C++17文件系统[编辑 | 编辑源代码]

介绍[编辑 | 编辑源代码]

C++17引入了<filesystem>库(正式名称为std::filesystem),提供了一套跨平台的文件和目录操作接口。该库基于Boost.Filesystem,允许开发者以统一的方式处理文件路径、遍历目录、检查文件属性以及执行文件操作(如复制、移动和删除)。

文件系统库的核心目标是:

  • 提供平台无关的路径表示
  • 支持递归目录遍历
  • 实现文件元数据查询(如大小、权限、类型)
  • 封装常见文件操作(如创建/删除目录)

核心组件[编辑 | 编辑源代码]

文件系统库主要包含以下类和函数:

组件 描述
std::filesystem::path 表示文件系统路径的类
std::filesystem::directory_entry 目录项信息(缓存文件属性)
std::filesystem::directory_iterator 非递归目录遍历器
std::filesystem::recursive_directory_iterator 递归目录遍历器
std::filesystem::file_status 文件类型和权限信息

基本用法[编辑 | 编辑源代码]

路径操作[编辑 | 编辑源代码]

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem; // 命名空间别名

int main() {
    // 构造路径对象
    fs::path p1 = "/usr/local/include";
    fs::path p2 = "config.h";
    
    // 路径拼接和规范化
    fs::path full_path = p1 / p2;
    std::cout << "完整路径: " << full_path << '\n'
              << "父目录: " << full_path.parent_path() << '\n'
              << "文件名: " << full_path.filename() << '\n'
              << "扩展名: " << full_path.extension() << '\n';
    
    // 路径存在性检查
    if (fs::exists(full_path)) {
        std::cout << "文件存在\n";
    }
}

输出示例(Linux系统):

完整路径: "/usr/local/include/config.h"
父目录: "/usr/local/include"
文件名: "config.h"
扩展名: ".h"
文件存在

文件操作[编辑 | 编辑源代码]

#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;

void demo_file_ops() {
    fs::path demo_dir = "test_dir";
    
    // 创建目录
    if (!fs::exists(demo_dir)) {
        fs::create_directory(demo_dir);
        std::cout << "目录创建成功\n";
    }
    
    // 创建空文件
    fs::path file1 = demo_dir / "data.txt";
    std::ofstream(file1).put('a'); // 创建文件并写入一个字符
    
    // 文件信息
    std::cout << "文件大小: " << fs::file_size(file1) << " bytes\n"
              << "最后修改时间: " << fs::last_write_time(file1).time_since_epoch().count() << '\n';
    
    // 复制文件
    fs::path file2 = demo_dir / "data_backup.txt";
    fs::copy_file(file1, file2);
    
    // 删除操作
    fs::remove(file1);
    fs::remove_all(demo_dir); // 递归删除目录
}

高级特性[编辑 | 编辑源代码]

目录遍历[编辑 | 编辑源代码]

递归遍历目录结构(使用mermaid展示流程):

graph TD A[开始遍历] --> B[打开目录] B --> C{是否还有条目?} C -->|是| D[获取当前条目] D --> E[处理文件/目录] E --> F[递归处理子目录?] F -->|是| B F -->|否| C C -->|否| G[结束遍历]

代码实现:

void list_files(const fs::path& dir_path) {
    try {
        for (const auto& entry : fs::recursive_directory_iterator(dir_path)) {
            auto status = entry.status();
            
            std::cout << (fs::is_directory(status) ? "[D] " : 
                         fs::is_symlink(status) ? "[L] " : "[F] ")
                      << entry.path() << '\n';
        }
    } catch (const fs::filesystem_error& e) {
        std::cerr << "错误: " << e.what() << '\n';
    }
}

文件系统空间[编辑 | 编辑源代码]

查询磁盘空间信息:

void show_disk_usage(const fs::path& path) {
    fs::space_info si = fs::space(path);
    
    std::cout << "在 " << path << ":\n"
              << "总空间: " << si.capacity/1'000'000 << " MB\n"
              << "可用空间: " << si.available/1'000'000 << " MB\n"
              << "空闲空间: " << si.free/1'000'000 << " MB\n";
}

错误处理[编辑 | 编辑源代码]

文件系统操作可能抛出std::filesystem::filesystem_error异常,最佳实践是:

  • 检查文件存在性(exists()
  • 捕获特定异常
  • 使用error_code参数的无异常版本

示例:

void safe_remove(const fs::path& p) {
    std::error_code ec;
    if (!fs::remove(p, ec)) {
        std::cerr << "删除失败: " << ec.message() << '\n';
    }
}

实际应用案例[编辑 | 编辑源代码]

场景: 实现一个简单的项目清理工具,删除构建目录中的所有临时文件(*.tmp, *.bak)

void clean_project(const fs::path& project_dir) {
    const std::vector<std::string> ext_to_remove = {".tmp", ".bak"};
    
    for (const auto& entry : fs::recursive_directory_iterator(project_dir)) {
        if (!entry.is_regular_file()) continue;
        
        const std::string ext = entry.path().extension().string();
        if (std::find(ext_to_remove.begin(), ext_to_remove.end(), ext) != ext_to_remove.end()) {
            std::cout << "删除: " << entry.path() << '\n';
            fs::remove(entry.path());
        }
    }
}

跨平台注意事项[编辑 | 编辑源代码]

  • Windows路径使用反斜杠(\),但path类会自动处理
  • 符号链接行为在不同系统上可能不同
  • 文件权限模型在Unix和Windows上有显著差异

性能考虑[编辑 | 编辑源代码]

  • directory_entry会缓存文件属性,减少重复系统调用
  • 递归遍历可能消耗较多内存,对于超大目录结构
  • 频繁调用last_write_time等函数可能影响性能

数学表示[编辑 | 编辑源代码]

文件系统空间计算可用百分比公式: 可用百分比=(availablecapacity)×100%

总结[编辑 | 编辑源代码]

C++17文件系统库提供了:

  • 统一的跨平台路径处理
  • 完整的文件和目录操作集合
  • 类型安全的接口设计
  • 异常和错误码双重错误处理机制

对于需要文件操作的现代C++项目,应优先使用std::filesystem而非平台特定API。