PHP遍历文件系统需据场景选方法:scandir()适合单层但需过滤.和..;递归首选RecursiveDirectoryIterator+RecursiveIteratorIterator;glob()内存开销大且跨平台问题多;opendir()/readdir()省内存但需防句柄泄漏。
PHP里遍历文件系统不是选“最短代码”,而是看场景:要单层还是递归?要过滤扩展名还是按权限跳过?内存是否受限?用错方法可能卡死或漏掉文件。
scandir() 适合单层快速列举,但必须手动处理 . 和 ..
它返回的是包含所有条目的数组,包括
和
,不加过滤直接传给
或拼路径会出错。
用
去掉特殊项
排序默认是字典序,
会排在
前面;需要自然排序就加
路径拼接必须用
或
,硬写
在 Windows 下会失效
不递归,想进子目录得自己写递归调用,容易栈溢出或无限循环(比如符号链接成环)
RecursiveDirectoryIterator + RecursiveIteratorIterator 是递归首选
这是 PHP 官方推荐的递归方式,比手写递归健壮得多,自动跳过不可读目录(只要加
),也支持
标志省去手动过滤。
初始化时传
,
和
就不会出现在迭代中
用
判断类型,别用
—— 后者可能因权限失败而返回 false,误判为非文件
遇到
会抛
,必须用
包裹
,否则整个遍历中断
如果只需要文件(不含目录),构造
时第三个参数用
glob() 看似简洁,但只适合小目录+固定模式
是一次性加载全部匹配结果到内存的,对含几千个文件的目录,很容易触发
或超时。它也不原生支持深度递归(
或
依赖系统 libc,跨平台行为不一致)。
PHP 8.5.5
PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。
下载
立即学习
“
PHP免费学习笔记(深入)
”;
模式里写
没问题,但写
在部分 PHP 版本或系统上会静默失败
无法跳过无权限目录,
遇到
类路径直接返回空数组,不报错也不提示,容易误以为“没文件”
返回的是纯路径字符串数组,没有元信息(如修改时间、大小),后续要查得再
一次,IO 开销翻倍
不能和
结合做前置检查——
本身不校验可读性
opendir() + readdir() 适合内存敏感场景,但易漏资源释放
它不预加载全部条目,边读边处理,内存占用稳定,适合遍历超大目录(比如日志归档目录)。但忘了
会导致句柄泄漏,尤其在长生命周期脚本(如 CLI 守护进程)中会累积。
每次
返回的是相对名,拼完整路径前先用
或
判断,避免对
/
调用
循环里不要在
条件中直接写
,万一
是空字符串或非法字符会出错
PHP 8.1+ 支持
类替代
,语法更干净:
Windows 下注意路径长度限制(MAX_PATH=260),长路径要用
前缀,
不支持,得换
真正麻烦的不是“怎么写”,而是权限异常、符号链接循环、超长路径、编码不一致(比如 FTP 上传的 UTF-8 文件名在某些 locale 下
返回乱码)——这些情况在测试环境常被忽略,上线后才暴露。
...is_file()array_filter($files, fn($f) => $f !== '.' && $f !== '..')file10.txtfile2.txtnatcasesort($files)DIRECTORY_SEPARATORrealpath()/try/catchSKIP_DOTSFilesystemIterator::SKIP_DOTS...$file->isFile()is_file($file->getPathname())Permission deniedUnexpectedValueExceptiontry/catchforeachRecursiveIteratorIteratorRecursiveIteratorIterator::LEAVES_ONLYglob()memory_limitGLOB_BRACE**$dir . '/*.php'$dir . '/**/*.php'glob()/procstat()is_readable()glob()closedir()readdir()is_dir()is_file()...stat()readdir()is_file($path . '/' . $f)$fDiropendir()$dir = dir($path); while (($f = $dir->read()) !== false) { ... } $dir->close();\?opendir()RecursiveDirectoryIteratorscandir()