0

0

c++怎么使用std::filesystem遍历文件夹_c++ 递归查找文件与权限修改【技巧】

穿越時空

穿越時空

发布时间:2026-01-01 15:49:02

|

727人浏览过

|

来源于php中文网

原创

应使用 try/catch 包裹迭代器初始化和递增操作,配合 directory_options::skip_permission_denied 和手动 while 循环遍历,禁用符号链接跟踪以避免崩溃;查找文件时优先用 is_regular_file() 和 extension() 判断,权限修改前需捕获 filesystem_error。

c++怎么使用std::filesystem遍历文件夹_c++ 递归查找文件与权限修改【技巧】

std::filesystem::recursive_directory_iterator 怎么用才不崩溃

直接用 std::filesystem::recursive_directory_iterator 遍历目录时,最常见崩溃原因是底层路径不可访问(比如权限不足、符号链接循环、挂载点失效),而默认构造器不捕获异常。必须显式处理 std::filesystem::filesystem_error

  • 永远用 try/catch 包裹迭代器初始化和递增操作,尤其在非受控环境(如用户目录、外部存储)中
  • 避免直接写
    for (auto& entry : std::filesystem::recursive_directory_iterator(path))
    —— 这会在首次 ++ 时触发访问,异常无法被 for 循环捕获
  • 改用 while 循环 + 手动递增,并在每次 ++iter 前检查 iter != std::filesystem::end(iter)
  • 传入 std::filesystem::directory_options::skip_permission_denied 可跳过无权读取的子目录,但注意:这仅影响「进入子目录」,不抑制对当前项元数据的读取失败

怎么安全地递归查找特定文件名或扩展名

不能依赖 entry.path().filename() 粗暴字符串匹配,因为大小写敏感性、编码、隐藏文件属性都可能出错;更可靠的是组合 entry.is_regular_file()entry.path().extension() 判断。

  • 扩展名比较务必用 == 而非 string::find:例如 entry.path().extension() == ".log",因为 .extension() 返回的是带点的 std::filesystem::path,不是裸字符串
  • 文件名精确匹配用 entry.path().filename() == "config.ini",注意它区分大小写(Windows 下通常不敏感,但标准行为是敏感)
  • 若需忽略大小写,先转小写再比:用 std::ranges::transform + std::tolower 处理 entry.path().filename().string(),但注意 locale 安全性,生产环境建议用 ICU 或平台 API
  • 不要在循环中反复调用 entry.status() —— 它可能触发额外系统调用;优先用 entry.is_regular_file() / entry.is_directory(),它们复用已缓存的状态

修改文件权限时 chmod 的跨平台陷阱

std::filesystem::permissions() 在 Windows 上只模拟 Unix 权限位(通过 ACL 子集),实际效果受限;Linux/macOS 下才真正映射到 chmod。直接设 owner_write 可能被静默忽略。

超级简历WonderCV
超级简历WonderCV

免费求职简历模版下载制作,应届生职场人必备简历制作神器

下载
  • 修改前先获取当前权限:auto old_perms = std::filesystem::status(path).permissions(),再按位操作,避免覆盖执行位等意外状态
  • Windows 下想禁用写入,请用 std::filesystem::perms::owner_write | std::filesystem::perms::group_write | std::filesystem::perms::others_write,然后 & ~ 写权限位;但注意:这等价于设置只读属性,而非 Unix 式 chmod
  • 批量修改时别用递归迭代器顺手改权限——std::filesystem::permissions() 对目录生效后,新创建文件会继承父目录默认权限(umask 影响),但已有子项不受影响;要真正递归改,得自己遍历并逐个调用
  • 权限修改失败时,std::filesystem::permissions()std::filesystem::filesystem_error,错误码可能是 std::errc::operation_not_permitted(Windows 管理员权限缺失)或 std::errc::read_only_file_system(挂载为 ro)

性能关键:什么时候该关掉递归遍历的 symlink 跟踪

默认情况下 recursive_directory_iterator 会跟随符号链接进入目标目录,导致重复遍历、无限循环甚至溢出。除非你明确需要解析软链内容,否则必须关掉。

立即学习C++免费学习笔记(深入)”;

  • 构造时传 std::filesystem::directory_options::none:这是最安全的默认选项,完全不跟踪 symlink
  • 如果只想跳过 symlink(不报错也不进入),用 std::filesystem::directory_options::skip_permission_denied | std::filesystem::directory_options::follow_directory_symlink 是错的——follow_directory_symlink 正是你要禁用的行为
  • 检测 symlink 用 entry.is_symlink(),它不触发访问,开销极低;可据此做白名单式放行(例如只允许进入特定可信路径下的 symlink)
  • 在 SSD 上遍历百万级小文件时,关闭 symlink 跟踪可减少 15%+ 的系统调用次数;配合 std::filesystem::directory_options::skip_permission_denied,整体耗时下降明显
实际递归查找并设只读的最小可行代码片段:
void find_and_chmod_ro(const std::filesystem::path& root, const std::string& ext) {
    std::error_code ec;
    for (std::filesystem::recursive_directory_iterator iter(root, std::filesystem::directory_options::skip_permission_denied, ec), end; iter != end && !ec; ++iter) {
        if (ec) break;
        auto& entry = *iter;
        if (entry.is_regular_file() && entry.path().extension() == ext) {
            try {
                std::filesystem::permissions(entry.path(),
                    std::filesystem::perms::owner_read | std::filesystem::perms::group_read | std::filesystem::perms::others_read,
                    std::filesystem::perm_options::replace);
            } catch (const std::filesystem::filesystem_error& e) {
                // 忽略权限修改失败,继续下一个
            }
        }
    }
}
Windows 下测试时记得以管理员身份运行,否则对 Program Files 类路径的 permissions() 调用大概率失败;Linux 下则要注意 umask 是否干扰最终权限位。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

312

2023.08.02

while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

81

2023.09.25

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

248

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

205

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1435

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

609

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

547

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

539

2024.04.29

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

62

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 6.4万人学习

Git 教程
Git 教程

共21课时 | 2.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号