PHP使用RecursiveDirectoryIterator遍历目录如何按字母排序保留层级结构
问题根源
你现在遇到directories字段为空的核心原因是RecursiveIteratorIterator默认使用RecursiveIteratorIterator::LEAVES_ONLY遍历模式,只会返回文件(叶子节点),不会返回目录节点,所以$file->isDir()的判断永远不会命中。
实现方案
不需要更换迭代器,只需要调整遍历模式、调整数组结构拼装逻辑,最后做轻量排序即可,完全可以保留原有迭代器的性能优势,修改后的代码如下:
function get_directory_contents($directory, $hide_index_files = TRUE, $limit_to_html_files = TRUE) { // 调整遍历模式为SELF_FIRST,会先返回目录节点,再返回其下内容 $rdi = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS); $rii = new RecursiveIteratorIterator($rdi, RecursiveIteratorIterator::SELF_FIRST); $result = ['files' => []]; $rootPathLength = strlen(rtrim($directory, '/') . '/'); foreach ($rii as $file) { // 先处理目录:提前初始化到结果数组,支持空目录展示 if ($file->isDir()) { $relativePath = substr($file->getPathname(), $rootPathLength); // 中文/特殊文件名兼容转码可选,不需要可以删掉 $relativePath = mb_convert_encoding($relativePath, 'UTF-8', 'GBK,UTF-8'); if (!isset($result['files'][$relativePath])) { $result['files'][$relativePath] = []; } continue; } // 过滤规则和原有逻辑一致 $filename = $file->getFilename(); if ($hide_index_files && $filename === 'index.html') { continue; } if ($limit_to_html_files && substr($filename, -5) !== '.html') { continue; } // 拼装路径 $fullRelativePath = substr($file->getPathname(), $rootPathLength); $dirRelativePath = substr($fullRelativePath, 0, -strlen($filename) - 1); // 根目录文件归到base_directory $dirKey = $dirRelativePath ?: 'base_directory'; // 把文件放到对应目录分组下 $result['files'][$dirKey][] = [ 'fullpath' => $fullRelativePath, 'filename' => $filename ]; } // 按字母序排序目录名 ksort($result['files'], SORT_NATURAL | SORT_FLAG_CASE); // 每个目录下的文件也按字母序排序 foreach ($result['files'] as &$fileList) { usort($fileList, function($a, $b) { return strnatcasecmp($a['filename'], $b['filename']); }); } unset($fileList); // 解除引用 return $result; }
关键修改说明
- 遍历模式改为
RecursiveIteratorIterator::SELF_FIRST,即可获取所有目录节点,空目录也会被提前初始化到结果数组中,解决空文件夹不展示的问题 - 直接按目录相对路径作为数组键存储对应文件列表,天然保留目录结构
- 最后使用
ksort对目录名做自然排序(不区分大小写),每个目录下的文件用usort做文件名自然排序,排序操作仅在内存中对结构化数组执行,几乎不会增加性能开销 - 原有文件过滤逻辑完全保留,符合你的业务需求
输出说明
返回的数组结构完全符合你的预期,你可以直接用这个结构渲染目录树,根目录的base_directory对应你要展示的/根路径。
内容的提问来源于stack exchange,提问作者Kaboom
相关产品推荐
相关产品推荐

