PHP遍历大量文件夹时部分图片/视频文件未列出求助
问题
我用以下PHP代码读取指定路径下各子文件夹中的PNG图片和MP4视频文件名,每个子文件夹仅包含1张图片和1个视频。当文件夹数量较少时代码运行正常,但遍历100个文件夹时,部分图片或视频会被遗漏,请求帮助排查问题。
<?php $gfg_folderpath = "C:\wamp\www\Films/"; // CHECKING WHETHER PATH IS A DIRECTORY OR NOT if (is_dir($gfg_folderpath)) { // GETTING INTO DIRECTORY $files = opendir($gfg_folderpath); { // CHECKING FOR SMOOTH OPENING OF DIRECTORY if ($files) { //READING NAMES OF EACH ELEMENT INSIDE THE DIRECTORY while (($gfg_subfolder = readdir($files)) !== FALSE) { // CHECKING FOR FILENAME ERRORS if ($gfg_subfolder != '.' && $gfg_subfolder != '..') { // echo "SUBFOLDER--" .$gfg_subfolder . "<br> // "."Files in ".$gfg_subfolder."--<br>"; $dirpath = "C:\wamp\www\Films/" . $gfg_subfolder . "/"; // GETTING INSIDE EACH SUBFOLDERS if (is_dir($dirpath)) { $file = opendir($dirpath); { if ($file) { //READING NAMES OF EACH FILE INSIDE SUBFOLDERS while (($gfg_filename = readdir($file)) !== FALSE) { $numbers = array(); if ($gfg_filename != '.' && $gfg_filename != '..') { // $mimeType = mime_content_type($gfg_filename); if(strtolower(end(explode(".",$gfg_filename))) =="png") { $vid= $gfg_filename . "<br>"; $numbers[0]=$gfg_filename; } if(strtolower(end(explode(".",$gfg_filename))) =="mp4") { $img= $gfg_filename . "<br>"; $numbers[1]=$gfg_filename; } echo $numbers[0]. "<br>".$numbers[1]. "<br>"; } } } } } echo "<br>"; } } } } } ?>
- 正常输出:每个子文件夹对应显示一行PNG文件名、一行MP4文件名,无遗漏
- 异常输出:部分子文件夹仅显示其中一个文件,甚至两个文件都不显示
问题排查与修复
核心问题分析
- 数组重复初始化导致输出混乱:
$numbers = array();写在子文件夹的文件循环内,每次读取一个文件就重置数组,导致第一次读取时只能赋值一个元素,空值直接输出;第二次读取才补全,但会重复输出,大量文件夹遍历易出现逻辑混乱。 - 未关闭目录句柄耗尽资源:每次
opendir后未调用closedir释放资源,遍历大量文件夹时会耗尽系统允许的文件句柄数量,后续目录无法打开直接遗漏文件。 - 扩展名判断逻辑脆弱:用
explode(".")获取扩展名,若文件名包含多个点(如image.v2.png),会导致扩展名判断错误。 - 路径分隔符混用有风险:Windows路径混用
\和/,虽PHP兼容但存在潜在路径解析问题。
修复后的代码
<?php // 使用DIRECTORY_SEPARATOR适配系统路径分隔符 $gfg_folderpath = "C:\wamp\www\Films" . DIRECTORY_SEPARATOR; if (is_dir($gfg_folderpath)) { $mainDirHandle = opendir($gfg_folderpath); if ($mainDirHandle) { while (($gfg_subfolder = readdir($mainDirHandle)) !== false) { if ($gfg_subfolder === '.' || $gfg_subfolder === '..') { continue; } $dirpath = $gfg_folderpath . $gfg_subfolder . DIRECTORY_SEPARATOR; if (is_dir($dirpath)) { // 每个子文件夹仅初始化一次存储数组 $mediaFiles = ['png' => '', 'mp4' => '']; $subDirHandle = opendir($dirpath); if ($subDirHandle) { while (($gfg_filename = readdir($subDirHandle)) !== false) { if ($gfg_filename === '.' || $gfg_filename === '..') { continue; } // 用pathinfo安全获取文件扩展名 $ext = strtolower(pathinfo($gfg_filename, PATHINFO_EXTENSION)); if ($ext === 'png') { $mediaFiles['png'] = $gfg_filename; } elseif ($ext === 'mp4') { $mediaFiles['mp4'] = $gfg_filename; } } // 及时关闭子目录句柄释放资源 closedir($subDirHandle); // 所有文件读取完成后统一输出 echo $mediaFiles['png'] . "<br>" . $mediaFiles['mp4'] . "<br><br>"; } } } // 关闭主目录句柄 closedir($mainDirHandle); } } ?>
修复说明
- 将数组初始化移到子文件夹循环内,确保每个子文件夹只初始化一次,读完所有文件后统一输出,避免重复输出和空值问题。
- 每次
opendir后调用closedir释放句柄,防止资源耗尽导致的目录无法打开。 - 改用
pathinfo获取扩展名,兼容含多个点的文件名,判断更可靠。 - 使用
DIRECTORY_SEPARATOR统一路径分隔符,适配不同操作系统,消除路径解析风险。
内容的提问来源于stack exchange,提问作者Habie
相关产品推荐
相关产品推荐

