点击查看代码
C++17 标准带来了 std::filesystem库, 提供了强大的工具来处理文件路径, 目录以及其他与文件系统相关的操作. 这篇文章适合 C++ 初学者以及希望掌握 C++17 新特性的开发者, 旨在帮助他们高效地完成文件系统相关任务.

什么是 std::filesystem?

std::filesystem 是 C++ 标准库的一部分, 位于 std::filesystem 名称空间中. 它提供了一个平台 独立的方式来与文件系统交互, 支持目录导航, 查询文件属性和实现文件操作等功能.

为什么使用 std::filesystem?

在 C++17 之前, 开发者依赖于平台特定的 API 或第三方库进行文件操作, 导致可移植性的挑战. 使用 std::filesystem, 您可以获得:

    跨平台支持: 为 Windows, linux 和 MACOS 提供统一的 API.
便据性: 提供相关文件操作的直观函数.
性能: 接口实现根据平台做了优化处理. std::filesystem 常用功能 1. 检查文件和目录是否存在 #include <filesystem>
#include <IOStream> namespace fs = std::filesystem; int main() {
fs::path filePath = "example.txt";
if (fs::exists(filePath)) {
std::cout << "文件存在!\n";
} else {
std::cout << "文件不存在.\n";
}
return 0;
} 为了保持代码简洁, 后续代码中将不再包含头文件和main函数体, 读者可以从文末的源码链接获取完整源代码. 2. 创建和删除目录 fs::path dirPath = "new_directory";
fs::create_directory(dirPath); // 创建单个目录
fs::remove(dirPath); // 删除目录 3. 遍历目录 fs::path dirPath = "."; // 当前目录
for (const auto& entry : fs::recursive_directory_iterator(dirPath)) {
std::cout << entry.path() << std::endl;
} 此示例会递归列出当前目录及其所有子目录中的文件和文件夹. 4. 查询文件属性 fs::path filePath = "example.txt";
if (fs::exists(filePath)) {
std::cout << "文件大小: " << fs::file_size(filePath) << " 字节\n";
std::cout << "是否为正解文件: " << fs::is_regular_file(filePath) << "\n";
std::cout << "文件最后修改时间: "
<< fs::last_write_time(filePath).time_since_epoch().count()
<< "\n";
} 5. 复制和重命名文件 fs::copy("source.txt", "destination.txt", fs::copy_options::overwrite_existing); // 复制文件
fs::rename("old_name.txt", "new_name.txt"); // 重命名文件 6. 处理符号链接 fs::path symlinkPath = "symbolic_link";
fs::path targetPath = "target_file";
fs::create_symlink(targetPath, symlinkPath); // 创建符号链接
if (fs::is_symlink(symlinkPath)) {
std::cout << symlinkPath << " 是符号链接, 指向 "
<< fs::read_symlink(symlinkPath) << std::endl;
} 路径相关操作 7.1 路径组合 // 1. 路径组合
fs::path base = "/home/user/documents";
fs::path file = "report.pdf";
fs::path fullPath = base / file; // 使用 / 操作符组合路径
std::cout << "组合路径: " << fullPath << std::endl; 输出 组合路径: "/home/user/documents/report.pdf" 7.2 获取路径组件 fs::path filepath = "/home/user/documents/report.pdf";
std::cout << "文件名: " << filepath.filename() << std::endl;
std::cout << "主文件名: " << filepath.stem() << std::endl;
std::cout << "扩展名: " << filepath.extension() << std::endl;
std::cout << "父路径: " << filepath.parent_path() << std::endl; 输出 文件名: "report.pdf"
主文件名: "report"
扩展名: ".pdf"
父路径: "/home/user/documents" 7.3 相对路径计算 fs::path p1 = "/home/user/documents";
fs::path p2 = "/home/user/pictures";
fs::path rel = fs::relative(p2, p1); // 计算从 p1 到 p2 的相对路径
std::cout << "相对路径: " << rel << std::endl; // ../pictures 输出 相对路径: "../pictures" 7.4 路径分解与迭代 fs::path complex = "/home/user/documents/work/report.pdf";
std::cout << "路径分解:" << std::endl;
for (const auto& part : complex) {
std::cout << " " << part << std::endl;
} 输出 路径分解:
"/"
"home"
"user"
"documents"
"work"
"report.pdf" 7.5 词法规范化路径 fs::path messy = "home/user/../user/./documents/report.pdf";
std::cout << "规范化路径: " << messy.lexically_normal() << std::endl; 输出 规范化路径: "home/user/documents/report.pdf" 7.6 路径比较 // 使用 std::filesystem::equivalent 检查两个路径是否指向同一文件
fs::path linkPath =
"link_to_report.pdf"; // 假设这是一个指向 report.pdf 的符号链接
fs::path actualPath = "documents/report.pdf";
try {
if (fs::equivalent(linkPath, actualPath)) {
std::cout << "路径 " << linkPath << " 和 " << actualPath
<< " 指向同一文件." << std::endl;
} else {
std::cout << "路径 " << linkPath << " 和 " << actualPath
<< " 不指向同一文件." << std::endl;
}
} catch (const fs::filesystem_error& e) {
std::cerr << "文件系统错误: " << e.what() << std::endl;
} 7.7 路径拼接 fs::path prefix = "backup_";
fs::path filename = "report.pdf";
fs::path newpath = prefix.string() + filename.string();
std::cout << "拼接路径: " << newPath << std::endl; 输出 拼接路径: "backup_report.pdf" 7.8 检查路径特性 fs::path checkPath = "/home/user/documents/report.pdf";
std::cout << "是否为绝对路径: " << checkPath.is_absolute() << std::endl;
std::cout << "是否有扩展名: " << checkPath.has_extension() << std::endl;
std::cout << "是否有文件名: " << checkPath.has_filename() << std::endl;
std::cout << "是否有父路径: " << checkPath.has_parent_path() << std::endl; 输出 是否为绝对路径: 1
是否有扩展名: 1
是否有文件名: 1
是否有父路径: 1 路径替换操作 fs::path modPath = "/home/user/documents/report.pdf";
modPath.replace_filename("newreport.doc");
std::cout << "替换文件名后: " << modPath << std::endl;
modPath.replace_extension(".txt");
std::cout << "替换扩展名后: " << modPath << std::endl; 输出 替换文件名后: "/home/user/documents/newreport.doc"
替换扩展名后: "/home/user/documents/newreport.txt" 注意事项: 路径操作是纯字符串操作, 不涉及实际文件系统
这些操作在 Windows 和 Unix 系统上都能正常工作
使用 / 操作符组合路径比直接字符串拼接更安全
lexically_normal() 可以清理路径中的 . 和 .. 最佳实践 错误处理:
使用异常处理来捕获和管理错误情况. 许多 std::filesystem 函数会抛出 std::filesystem::filesystem_error, 例如在没有删除权限时. 路径类型:
使用 fs::absolute 将相对路径转换为绝对路径, 以确保路径的完整性和清晰性. 性能优化:
对于网络磁盘或涉及大量文件的操作, 尽量减少 I/O 操作以提高性能. 跨平台注意事项:
路径格式: 虽然 std::filesystem 自动处理不同平台的路径分隔符差异(Windows 使用 \, 其他平台使用 /), 但建议始终使用 fs::path 进行路径操作.
文件权限: 不同平台的文件权限管理可能不一致, 尤其是 fs::permissions. 路径组合:
使用 / 操作符组合路径比直接字符串拼接更安全. 路径规范化:
使用 lexically_normal() 清理路径中的 . 和 .., 以获得更简洁的路径表示. 限制性 调用链接文件: 包含链接文件的操作在不同平台上有不同表现.
性能: 尽管高效, 部分文件系统操作在网络磁盘上仍会突出慢. 结论 std::filesystem 库是 C++ 重要的增加, 使文件和目录操作更加简单和可移植. 无论您是在写一个简单脚本, 还是构建复杂应用, 熟练该库都是值得一试的. 开始探索 std::filesystem, 你将发现它是你 C++ 程序装备中一个珍贵的工具!

到此这篇关于C++17 Filesystem 实用教程的文章就介绍到这了

C++17 Filesystem 实用教程的更多相关文章

  1. 《Java2 实用教程(第五版)》学习指导

    <Java2 实用教程(第五版)> 第1章Java入门 主要内容:P1 1.1Java的地位:P1 1.2Java的特点:P2 1.3安装JDK:P5 1.4Java程序的开发步骤:P8 ...

  2. 蓝牙BLE实用教程

    蓝牙BLE实用教程 Bluetooth BLE 欢迎使用 小书匠(xiaoshujiang)编辑器,您可以通过 设置 里的修改模板来改变新建文章的内容. 1.蓝牙BLE常见问答 Q: Smart Re ...

  3. Unix sed实用教程系列目录[已完成]

    本系列文章已经译完了,译自awk-sed@theunixschool,收获颇丰,作者没有讲明白的我做了补充,并且尝试讲的更清楚,整理成系列索引,方便学习,开篇非译文,是我为了方便后面的理解写的一篇,感 ...

  4. 学习笔记之Java程序设计实用教程

    Java程序设计实用教程 by 朱战立 & 沈伟 学习笔记之JAVA多线程(http://www.cnblogs.com/pegasus923/p/3995855.html) 国庆休假前学习了 ...

  5. js模版引擎handlebars.js实用教程

    js模版引擎handlebars.js实用教程 阅读本文需要了解基本的Handlebars.js概念,本文并不是Handlebars.js基础教程,而是注重于实际应用,为读者阐述使用过程中可能会遇到的 ...

  6. iptables实用教程(二):管理链和策略

    概念和原理请参考上一篇文章"iptables实用教程(一)". 本文讲解如果管理iptables中的链和策略. 下面的代码格式中,下划线表示是一个占位符,需要根据实际情况输入参数, ...

  7. iptables实用教程(一):基本概念和原理

    概述 iptables是linux自带的防火墙软件,用于配置IPv4数据包过滤或NAT(IPv6用ip6tables). 在linux上,防火墙其实是系统内核的一部分,基于Netfilter构架,基本 ...

  8. 《UNIX实用教程》读书笔记

    原著:<Just Enough UNIX>  Fifth Edition  [美]Paul K.Andersen 译著:<UNIX实用教程> 第5版 宋虹 曾庆冬 段桂华 杨路 ...

  9. MUI 实用教程

    MUI 实用JS教程: https://www.kancloud.cn/benhailong/mui/319751  MUI 实用教程: https://www.kancloud.cn/benhail ...

  10. 《Java2 实用教程(第五版)》教学进程

    目录 <Java2 实用教程(第五版)>教学进程 预备作业1:你期望的师生关系是什么? 预备作业2 :学习基础和C语言基础调查 预备作业3:Linux安装及命令入门 第一周作业 第二周作业 ...

随机推荐

  1. postgresql序列重复问题处理

    问题 在执行数据插入时,postgresql 提示more than one owned sequence found错误.这个和之前文章中写的序列编号错乱不同,是由数据表的一个列生成了多个序列导致的 ...

  2. Collector的配置和使用

    目录 Collector的配置和使用 Collector配置 Receivers Processors Exporters Service Extensions 使用环境变量 Collector的使用 ...

  3. H2数据UNIX_TIMESTAMP兼容问题

    开篇  今天某同事在spring结合H2实现mybatis DAO层单测的时候遇到一个问题,本着人道主义临时支持下我司大xx业务,就帮忙一起看了下,回想一下整个过程还是挺有意思的,就顺便写了这篇文章来 ...

  4. Qt/C++地图测距/显示不同线段的距离/拿到测距结果/测距结束信号

    一.前言说明 地图测距在地图组件中属于一个比较小众的功能,但是又不得不提供,有时候用户希望直接在地图上选点,测算距离,尤其是在一些军事领域用的比较多,测距功能提炼出来的共性就是,每一段都有距离,最后鼠 ...

  5. Qt数据库应用10-通用数据库设置

    一.前言 做过了众多的项目,只要是用了数据库的项目,基本上还有一个需求就是,提供一个界面用来初始化数据库,相当于恢复出厂设置的数据,一般恢复出厂设置需要复位的是配置文件.数据库文件.布局文件这几种,其 ...

  6. Qt编写的项目作品22-自定义委托全家桶

    一.功能特点 可设置多种委托类型,例如复选框/文本框/下拉框/日期框/微调框/进度条等. 可设置是否密文显示,一般用于文本框. 可设置是否允许编辑,一般用于下拉框. 可设置是否禁用,一般用来禁用某列. ...

  7. JSON解析的这6种方案,真香!

    前言 在 Java 开发中,解析 JSON 是一个非常常见的需求. 不管是和前端交互.调用第三方接口,还是处理配置文件,几乎都绕不开 JSON. 这篇文章总结了6种主流的 JSON 解析方法,希望对你 ...

  8. Verilog5_有限状态机

    一.有限状态机(Finite State Machine, FSM)基本概念 有限状态机是由寄存器组和组合逻辑构成的硬件时序电路:         其状态只能在同一时钟跳变沿从一个状态转向另一个状态: ...

  9. Java中StringBuilder类常用的几个方法

    StringBuilder类 StringBuilder 类是 Java 中用于处理可变字符串的类,它提供了在字符串内部进行修改的方法,相比之下,String 类是不可变的,每次对字符串做修改都会创建 ...

  10. Vim编辑器退出的多种方法

    当文本编辑结束之后,通常需要退出编辑器.退出编辑器又分为4种情况:保存退出.正常退出.不保存退出及强制退出.下面简单说下吧!   1.先介绍一下保存退出.当我们编辑或修改好了文件内容,如图.   我们 ...