PHP遍历目录排除特定文件类型怎么做_PHP过滤文件扩展名指南【技巧】

2次阅读

PHP遍历目录排除特定文件类型怎么做_PHP过滤文件扩展名指南【技巧】

scandir() + 手动过滤最可控

php 没有内置“排除某类扩展名”的目录遍历函数,scandir() 返回所有条目,后续靠 pathinfo()字符串判断来筛。好处是逻辑透明、兼容性好(PHP 4+ 都行),坏处是你得自己写过滤条件。

常见错误是只检查文件名后缀而忽略大小写,比如 .JPG 被漏掉;或者没跳过 ... 导致递归出错。

  • 先用 scandir($dir) 获取全部项,再 array_filter() 处理
  • 对每个项调用 is_file($full_path) 确保是文件(避免把子目录当文件过滤)
  • strtolower(pathinfo($file, PATHINFO_EXTENSION)) 统一小写再比对,避免大小写陷阱
  • 排除数组里的 '.''..' —— 这俩不是文件也不是真实目录项,只是导航符号

RecursiveDirectoryIterator 配合 accept() 方法更面向对象

如果要递归遍历子目录,且想在迭代器层面就过滤掉不需要的扩展名,RecursiveDirectoryIterator 是更干净的选择。它本身不支持直接传入黑名单,但可以继承并重写 accept() 方法。

容易踩的坑是:忘记调用父类accept() 导致连目录都不进;或者在 accept() 里用了 file_exists()is_file(),其实迭代器已经提供了 $this->isFile(),更轻量。

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

  • 只在 $this->isFile() === true 时检查扩展名,跳过目录和特殊项
  • 黑名单用 in_array(strtolower($ext), $blacklist) 判断,别用 strpos() 防止 .tar.gz 误匹配 .tar
  • 构造 RecursiveIteratorIterator 时加 RecursiveIteratorIterator::LEAVES_ONLY,避免返回空目录节点

glob() 快速单层过滤,但不支持递归和复杂逻辑

glob() 写起来最短,比如 glob($dir . '/*.php') 只取 PHP 文件。但它天生只能“白名单”式匹配,要“排除”就得绕一下:先取全部,再取要排除的,最后用 array_diff()

性能上,glob() 在大目录里可能比 scandir() 慢,因为 shell 层做了通配展开;而且 windows 下对大小写不敏感,linux 下敏感,行为不一致。

  • 单层过滤推荐:array_diff(glob($dir . '/*'), glob($dir . '/*.log'), glob($dir . '/*.tmp'))
  • 别对 glob($dir . '/*') 结果直接 foreach 后用 is_dir() 判,那会多一次系统调用
  • 路径末尾必须带 /,否则 $dir . '*.php'$dir 无结尾斜杠时会拼错

扩展名判断别硬编码 substr(),用 pathinfo() 更稳

有人用 substr($file, -4) === '.php',这在 index.php.bak 上就挂了。还有人用 explode('.', $file) 取最后一段,遇到 archive.tar.gz 就返回 gz 而不是 tar.gz

pathinfo() 是唯一能正确处理多点分隔、隐藏文件(如 .gitignore)、无扩展名文件的方案。注意它返回的是关联数组,键名固定,别拼错 PATHINFO_EXTENSION

  • 始终用 pathinfo($file, PATHINFO_EXTENSION),不要自己切字符串
  • 空扩展名(如 /bin/sh)返回空字符串,检查时用 === '',别用 empty()
  • 如果文件路径含中文或特殊字符,确保脚本和文件系统编码一致,否则 pathinfo() 可能返回乱码扩展名

真正麻烦的不是怎么写过滤逻辑,而是目录里混着软链接、权限受限文件、正在被写的临时文件——这些在 is_file()stat() 阶段就可能抛 Warning,得提前用 @ 抑制或 clearstatcache() 配合处理。实际跑的时候,永远比本地测试多出三类意外。

text=ZqhQzanResources