点击查看代码
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. 【前端】【JavaScript】通过成绩判断等级

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. 【Linux】职教云作业

    作业_职教云_Day01 @ 哔哩哔哩 萌狼蓝天 1.由普通用户切换到root用户 su 2.列出home目录下的各个文件名字 cd /home ls 3.在/etc/目录下显示以sysc开头的所有命 ...

  3. iOS app 自动化测试 - 环境搭建

    1. 基本前提 安装好了 mac 上自动化测试的基本环境 如果没有,可以参考这一个: 2. iOS appium python自动化测试环境搭建 2.1 真机环境 2.1.1 前提:安装了 appiu ...

  4. docker.sock: connect: permission denied 解决

    问题描述xjun@DESKTOP-L2R4GKN:~$ docker run -it hello-worlddocker: Got permission denied while trying to ...

  5. 龙哥量化:通达信板块概念FAQ,*期强势、*期弱势是怎么划分的?等问题是官网的解释,股友可以根据文章的提示迸发策略灵感

    如果您需要代写公式, 请联系我. 龙哥QQ:591438821 龙哥微信:Long622889 比如第9条,*期强势:20日涨幅>=30%,     3日涨幅>0,非停牌.非ST.非未开板 ...

  6. Qt/C++编写网络摄像头推流(4路1080P主码流只占用0.2%CPU/极低延时极速响应)

    一.前言说明 将从网络摄像头拉流过来的视频流重新推流出去,是目前一个很常规的做法,尤其是推流到流媒体服务中心,这样流媒体服务中心就把散落在各个区域的监控摄像头集中起来统一管理,同时提供对外一致的访问接 ...

  7. Qt音视频开发25-ffmpeg音量设置

    一.前言 音视频的播放.关闭.暂停.继续这几个基本功能,绝大部分人都是信手拈来的搞定,关于音量调节还是稍微饶了下弯弯,最开始打算采用各个系统的api来处理,坐下来发现不大好,系统的支持不完美,比如有些 ...

  8. WxPython跨平台开发框架之图标选择界面

    在使用 wxPython 开发跨平台桌面应用程序时,创建一个图标选择界面通常用于让用户从图标资源库中选择图标,我们可以把图标分为自定义的图标资源和系统的图标资源两大类,最终我们把它们整合一起使用,在框 ...

  9. Redis 源码简洁剖析 08 - epoll

    select, poll, epoll 源码分析 参考链接 Redis 源码简洁剖析系列 select, poll, epoll 关于 select, poll, epoll,​网络 IO 演变发展过 ...

  10. Solution Set - “带我去看极光与大海吧”

    目录 0.「AGC 062C」Mex of Subset Sum 1.「THUPC 2021 初赛」「洛谷 P7136」方格游戏 2.「THUPC 2023 初赛」「洛谷 P9139」喵了个喵 II ...