c17新特性 文件操作 filesystem

需求

项目中需要对文件进行curd,或者对文件信息进行输出打印等操作。本文根据参考文献进行修改,主题是简洁,低代码。筛选关键的代码。详细可看参考文献。

理论

C++17 中引入了 std::filesystem 库,它提供了一组用于操作文件系统的类和函数。这个库使得我们在 C++ 中处理文件和目录变得更加简单和跨平台。

历史背景

C++ Filesystem库是C++17标准的一部分,它的出现填补了C++长久以来在文件和目录操作方面的空白。在这之前,开发者通常需要使用操作系统特定的API或第三方库。现在不需要寻找特定三方库嵌入到项目中,太麻烦了,支持c17标准就能实现

年份发展事件
2011Boost Filesystem库发布
2014C++14标准发布,但未包含Filesystem库
2017C++17标准发布,正式引入Filesystem库

技术对比

特性C++ Filesystem传统C++ I/OPython I/O
代码简洁性
性能
平台兼容性

实践

 如何在项目中引入Filesystem库

// 引入头文件
#include <filesystem>
// 使用命名空间
namespace fs = std::filesystem;

curd操作

读写文件我们单独演示,因为比较重要

路劲操作:
拼接:
full_path = base_path / file;  输出:/home/user/documents/file.txt
解析:
fs::path p = "/home/user/documents/file.txt";
p.parent_path()    输出:/home/user/documents
p.filename()       输出:file.txt
p.extension()      输出:.txt
p.stem()           输出:file



文件和目录操作:
create_directory   创建目录
create_directories    创建多级目录
exists 检查文件或目录是否存在。
is_regular_file 和 is_directory 等函数检查文件类型。

copy 和 copy_file 复制文件或目录。
选项:
copy_options::update_existing: 如果 to_path 已存在且更新时间较新,则不复制。
copy_options::recursive: 递归复制目录及其子项。
copy_options::overwrite_existing: 始终覆盖现有文件。
copy("source.txt", "destination.txt", fs::copy_options::overwrite_existing | fs::copy_options::recursive);


remove 和 remove_all 删除文件或目录。
rename 文件重命名


文件属性获取:
file_size 获取文件大小。
last_write_time 获取文件最后修改时间。
status 获取文件状态信息,包括权限、所有者等。


目录遍历: 在遍历目录时,你可以选择深度优先或广度优先。深度优先通常用于搜索操作,而广度优先则更适用于快速查找。
directory_iterator 用广度优先遍历目录中的文件和子目录。
recursive_directory_iterator 用于深度优先递归遍历目录树。

综合运用 


#include <iostream>
#include <filesystem>

namespace fs = std::filesystem;

int main() {
    
    const std::string directory_path= "/path/to/your/directory";

    for (const auto& entry : fs::directory_iterator(directory_path)) {
        if (fs::is_regular_file(entry)) {
            std::cout << "文件名: " << entry.path().filename() << ", 大小: " << fs::file_size(entry) << " bytes" << std::endl;
        }
    }

    return 0;
}

文件读写

文件读取和写操作 一般配合I/O 操作来读取文件内容即ifstream和ofstream

模式

标准输入/输出模式:
std::ifstream: 用于从文件中读取数据。
std::ofstream: 用于向文件中写入数据。
std::fstream: 可以同时读取和写入文件。
文件打开模式:
std::ios::in: 以只读模式打开文件。
std::ios::out: 以只写模式打开文件。
std::ios::app: 以追加模式打开文件,写入数据时会添加到文件末尾。
std::ios::trunc: 以截断模式打开文件,如果文件存在,则会清空文件内容。
std::ios::binary: 以二进制模式打开文件,不进行任何文本格式转换。
文件定位模式:
std::ios::beg: 从文件开头开始定位。
std::ios::cur: 从当前位置开始定位。
std::ios::end: 从文件末尾开始定位。

举例:
std::ofstream file("example.txt", std::ios::app);

高端操作 

后续展示,先做个总结。

方法优点缺点适用场景
缓冲区(Buffering)减少I/O次数,提高性能需要额外的内存大量数据读写
异步I/O充分利用CPU,提高响应性代码复杂度可能增加I/O密集型应用
内存映射快速文件访问可能增加内存使用频繁访问的大文件
批量操作减少总体开销需要一次性处理所有任务多个小操作需要合并时

读取文件

基本操作

std::ifstream file("example.txt");
 std::string line;
while (std::getline(file, line)) {
    std::cout << line << std::endl;
 }

异步IO读


#include <iostream>
#include <fstream>
#include <future>
void async_read(const std::string& file_name) {
    std::ifstream infile(file_name, std::ios::in);
    std::string content;
    // 异步读取文件
    auto future = std::async(std::launch::async, [&]() {
        std::getline(infile, content);
    });
    // 在这里可以做其他事情
    future.wait();
    std::cout << "File content: " << content << std::endl;
}

文件内存映射

// 使用Boost库进行内存映射
#include <boost/iostreams/device/mapped_file.hpp>
int main() {
    boost::iostreams::mapped_file_source file("example.txt");
    auto data = file.data();
    // 直接访问内存中的数据
}

写入文件

写入缓冲区

std::ofstream outfile("example.txt", std::ios::out | std::ios::binary);
std::vector<char> buffer(1024);
// 填充缓冲区
outfile.write(buffer.data(), buffer.size());
outfile.close();

批量删除

std::vector<std::filesystem::path> files_to_delete = {/* ... */};
 for (const auto& file : files_to_delete) {
        std::filesystem::remove(file);
  }

错误处理和异常

三种常见异常

  • std::filesystem::filesystem_error(文件系统错误)
  • std::bad_alloc(内存分配失败)
  • std::invalid_argument(无效参数)

处理和捕获

当文件或目录不存在和权限不足
try {
    std::filesystem::remove("/path/to/non/existent/file");
} catch (const std::filesystem::filesystem_error& e) {
    std::cerr << "错误: " << e.what() << std::endl;
}

当系统无法分配足够的内存空间时,会抛出这种异常。 近期微软蓝屏事件bug
try {
    char* myarray= new char[1000000000ul];
} catch (std::bad_alloc& e) {
    std::cerr << e.what() << std::endl;
}

自定义抛出信息
try {
    std::filesystem::path p("");
    if (p.empty()) {
        throw std::invalid_argument("Path cannot be empty");
    }
} catch (const std::exception& e) {
    std::cerr << e.what() << std::endl;
}
方法优点缺点
使用标准异常代码可读性好,易于维护可能不满足特殊需求
不要滥用异常提高程序效率需要更多的错误检查代码
清理资源避免内存泄漏需要额外的代码

参考文献

【C++ 17 新特性 文件管理】探索C++ Filesystem库:文件和目录操作的全面指南(一)-阿里云开发者社区 (aliyun.com)

 【C++ 17 新特性 文件管理】探索C++ Filesystem库:文件和目录操作的全面指南(二)-阿里云开发者社区 (aliyun.com)

 

 总结

学习和使用filesystem有利于我们开发出跨平台的应用,而且函数封装的很好,值得我们学习,以最少的时间,做出正确的效果。

参考文献写的很详细,如果读取本文还有不懂得,可以进入文献,进一步的学习,开拓视野。

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值