尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

C++ STL之filesystem文件系统库详解

C++ STL之filesystem文件系统库详解
📅 发布时间:2026/7/4 4:27:53

C++ STL之filesystem文件系统库详解

一、从 Boost 到标准库:filesystem 的前世今生

C++17 之前,跨平台文件操作是噩梦。Windows 用GetFileAttributesW、Linux 用stat、Mac 用NSFileManager——每套 API 各有千秋,但无一适用于跨平台场景。多数项目转向boost::filesystem,但 Boost 毕竟不是标准,团队引入需额外依赖、配置构建链。

C++17 正式将std::filesystem纳入标准库,头文件<filesystem>,命名空间std::filesystem。它统一了路径分隔符(/vs\)、文件属性提取、目录遍历、磁盘容量查询等操作,且无第三方依赖。

#include<filesystem>namespacefs=std::filesystem;intmain(){fs::path p="/home/user/file.txt";boolexists=fs::exists(p);return0;}

二、path 类与正规化

path是 filesystem 库的核心类型,负责跨平台路径表示。它不检查路径是否真实存在,只做字符串操作。

常见操作

操作说明
p.root_name()返回根名(Windows 的C:)
p.root_directory()返回根目录(/或\)
p.parent_path()父路径
p.filename()文件名(含后缀)
p.stem()不带后缀的文件名
p.extension()后缀(含.)

正规化:lexically_normal

移除路径中的.、..和多余分隔符,返回逻辑上"干净"的路径。

fs::path p="a/./b/../c/file.txt";fs::path norm=p.lexically_normal();// 结果: "a/c/file.txt"

如果路径中有.表示当前目录,..表示上一级父目录,lexically_normal会将它们约简。注意这是纯字符串操作,不会访问磁盘。

make_preferred

将路径分隔符转为当前平台惯用格式:Windows 转\,POSIX 转/。

fs::path p="a/b/c";p.make_preferred();// Windows: a\b\c, Linux: a/b/c

原始路径: a/./b/../c/file.txt

lexically_normal

去除 .

回退 ..

正规化结果: a/c/file.txt

make_preferred

Windows: a\\b\\c

POSIX: a/b/c

三、directory_entry 的缓存机制

directory_entry封装了文件系统的一条记录,包括路径和属性。它的核心设计是缓存:首次访问文件属性后,结果会被内部缓存,后续访问不再触发系统调用。

fs::directory_entryentry("/home/user/file.txt");autosize1=entry.file_size();// 触发 statautosize2=entry.file_size();// 返回缓存,无系统调用entry.refresh();// 强制刷新缓存autosize3=entry.file_size();// 重新 stat

这在遍历大量文件时能显著减少 I/O:一次directory_iterator操作自动填充directory_entry,后续取file_size、last_write_time、file_type等都走缓存。

四、目录遍历:directory_iterator 与 recursive_directory_iterator

两套 API 对应两种遍历范围:

特性directory_iteratorrecursive_directory_iterator
遍历深度仅当前目录递归子目录
是否含...否否
排序未定义未定义
跳过子目录不适用disable_recursion_pending()
voidlist_all(constfs::path&dir){fs::directory_iterator end;for(autoit=fs::directory_iterator(dir);it!=end;++it){// 只有第一层}for(autoit=fs::recursive_directory_iterator(dir);it!=fs::recursive_directory_iterator();++it){// 递归全部if(it->is_directory()&&skip(*it))it.disable_recursion_pending();}}

是

否

是

是

否

否

开始遍历

选择迭代器类型

directory_iterator?

recursive_directory_iterator?

打开当前目录

读取下一个条目

还有条目?

返回 directory_entry

结束

打开当前目录

读取下一个条目

还有条目?

是目录且
未禁用递归?

递归进入子目录

返回 directory_entry

两种迭代器返回的都是directory_entry,可直接调用is_regular_file()、file_size()、path()等。

五、space_info:磁盘容量查询

std::filesystem::space()返回space_info结构体:

structspace_info{uintmax_t capacity;// 总容量uintmax_t free;// 剩余容量(给调用者的配额)uintmax_t available;// 可用容量(含非特权用户的配额限制)};
fs::space_info si=fs::space("/");std::cout<<"总容量: "<<si.capacity/1e9<<" GB\n";std::cout<<"剩余: "<<si.free/1e9<<" GB\n";std::cout<<"可用: "<<si.available/1e9<<" GB\n";

free与available的区别:POSIX 系统上,free是文件系统层未使用的块数,available还要扣除 root 预留块。非 root 用户看到available小于free。

六、copy 与 copy_options

fs::copy复制文件或目录,搭配copy_options控制行为:

选项效果
none默认,已存在时报错
skip_existing跳过已有文件,不报错
overwrite_existing覆盖已有文件
update_existing仅目标更旧时才覆盖
recursive递归复制子目录
directories_only仅复制目录结构
create_symlinks复制为符号链接
voidbackup(constfs::path&src,constfs::path&dst){fs::copy_options opts=fs::copy_options::recursive|fs::copy_options::overwrite_existing|fs::copy_options::update_existing;fs::copy(src,dst,opts);}

注意fs::copy在目录上默认不递归,必须显式加copy_options::recursive才能复制子目录。

七、面试题精选

1.lexically_normal会访问磁盘吗?

不会。它是纯字符串操作,只处理./和../路径分量,不检查文件是否存在。如果需要解析符号链接或相对路径的绝对化,用canonical或weakly_canonical(会访问磁盘)。

2.directory_iterator返回的条目有顺序保证吗?

没有。遍历顺序由底层文件系统决定,不可预测。若需有序遍历,须手动收集到std::vector再排序。

3.directory_entry缓存什么时间生效?如何刷新?

首次调用file_size()、last_write_time()、status()等触发系统调用后缓存结果。文件在外部被修改时缓存变脏,需调用refresh()刷新。缓存不自动感知外部变更。

4.copy_options::recursive和copy_options::directories_only可以同时使用吗?

可以。组合后会在目标递归创建完整的目录结构,但不复制任何文件。常用于备份前建好骨架。

5.space_info::free和space_info::available实际有什么区别?

free是文件系统层空闲块,available还要排除特权预留(ext4 默认 5% 给 root)。用户态程序应优先读available,否则写的字节可能被ENOSPC拒绝。

6.path的operator/=做了什么?与字符串拼接有何不同?

operator/=会自动插入平台分隔符(/或\),且不会重复。字符串拼接可能导致a//b或a\b混用。优先用operator/=而不是fs::path(a.string() + "/" + b.string())。

7.recursive_directory_iterator如何跳过某个子目录?

调用disable_recursion_pending(),析构后迭代器会跳过当前条目(须是目录)下的所有内容。

for(autoit=fs::recursive_directory_iterator(".");it!=fs::recursive_directory_iterator();++it){if(it->path().filename()==".git")it.disable_recursion_pending();elseprocess(*it);}

8. 如何判断一个path是绝对路径?

  • p.is_absolute():检查是否绝对路径(POSIX 以/开头,Windows 含根名+根目录)
  • p.is_relative():上述取反

Windows 上C:/foo是绝对路径,.是相对路径,/foo仅含根目录但无根名,按 Windows 规则也是相对路径。

相关新闻

  • 基于 SIMetrix/SIMPLIS 与 MATLAB/Simulink 协同仿真的超高开关频率(MHz级)DC-DC 建模实战教程
  • 202636读书笔记|《重走三毛之路:我们活在现在,不活在将来》——不被既有的规则所束缚,勇于突破
  • 【皇榜科技线路板质量课堂·第30篇】散布图(Scatter Plot):压合温度与剥离强度的关系,看图说话

最新新闻

  • 从理论到实践:gh_mirrors/yo/yolo_research中SwinTransformerV2注意力机制的应用详解
  • 一键修复与安装脚本:Linux服务器运维的自动化解决方案
  • Maven依赖管理完全教程:告别JAR包地狱的终极指南
  • ehentai-qt开发者指南:从源码结构到API调用的实战教程
  • nginx-auth-ldap核心参数解析:url、binddn与group_attribute配置技巧
  • 通往AGI的具身之路——TVA自适应协同进化系统(7)

日新闻

  • STM32F745VG与MC6470 IMU的高性能姿态控制系统设计
  • 机器不消费,人何以生存
  • AI项目操作手册编写规范与最佳实践

周新闻

  • Windows字体自定义终极方案:No!! MeiryoUI完全指南
  • Deepin Boot Maker:告别命令行,3分钟制作Linux启动盘的智能解决方案
  • Plain Craft Launcher 2:重新定义你的Minecraft游戏体验

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号