| 方法 | 返回值 | 遞歸支持 | 過濾模式 | 性能/記憶體 | 推薦場景 |
|---|---|---|---|---|---|
| scandir() | 文件名數組 | 手動遞歸 | 無 (需自行過濾) | 一次性載入全部,大目錄佔記憶體 | 小目錄、簡單列表 |
| glob() | 匹配路徑數組 | 手動遞歸 | 通配符 + GLOB_BRACE | 同 scandir,但可預過濾 | 按模式匹配文件 |
| opendir/readdir | 資源句柄 → 逐個讀取 | 手動遞歸 | 無 | 流式讀取,記憶體常數級 | 超大目錄、需精細控制 |
| RecursiveDirectoryIterator (SPL) | 迭代器對象 | 內建遞歸 | RegexIterator 過濾 | 延遲加載,面向對象 | 現代框架、複雜遍歷邏輯 |
<?php
function getFilesScandir($path) {
$files = [];
foreach (scandir($path) as $item) {
if ($item === '.' || $item === '..') continue;
$full = $path . DIRECTORY_SEPARATOR . $item;
if (is_dir($full)) {
$files = array_merge($files, getFilesScandir($full));
} else {
$files[] = $full;
}
}
return $files;
}
// 使用
$allFiles = getFilesScandir(__DIR__);
print_r($allFiles);
?>
優點:代碼簡潔;缺點:大目錄下 array_merge 效率低、遞歸深度受限於 xdebug.max_nesting_level。
<?php
function getFilesGlob($pattern) {
$files = [];
foreach (glob($pattern, GLOB_BRACE) as $item) {
if (is_dir($item)) {
$files = array_merge($files, getFilesGlob($item . DIRECTORY_SEPARATOR . $pattern));
} else {
$files[] = $item;
}
}
return $files;
}
// 同時匹配多種副檔名
$pattern = '{*.php,*.html,*.css,*.js}';
$files = getFilesGlob(__DIR__ . DIRECTORY_SEPARATOR . $pattern);
print_r($files);
?>
關鍵點:GLOB_BRACE 允許 {a,b,c} 多模式匹配,glob() 自動過濾 . 和 ..。
<?php
function traverseDir($path = '.') {
$handle = opendir($path);
if (!$handle) return;
while (($file = readdir($handle)) !== false) {
if ($file === '.' || $file === '..') continue;
$full = $path . DIRECTORY_SEPARATOR . $file;
if (is_dir($full)) {
echo "Directory: $file\n";
traverseDir($full);
} else {
echo "File: $full\n";
}
}
closedir($handle);
}
traverseDir('/var/www/html');
?>
優勢:不將所有文件名載入內存,適合百萬級文件目錄;可精細控制讀取流程 (如限制深度、並發處理)。
<?php
// 遞歸遍歷所有文件
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(__DIR__, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($iterator as $file) {
echo $file->getPathname() . "\n";
}
// 只取 .php 文件
$phpFiles = new RegexIterator($iterator, '/\.php$/i');
foreach ($phpFiles as $file) {
echo $file->getPathname() . "\n";
}
// 獲取文件信息
foreach ($iterator as $file) {
if ($file->isFile()) {
printf("%s %d bytes %s\n",
$file->getPathname(),
$file->getSize(),
date('Y-m-d H:i:s', $file->getMTime())
);
}
}
?>
核心類:
RecursiveDirectoryIterator:目錄樹迭代器RecursiveIteratorIterator:將遞歸迭代器扁平化為單層遍歷RegexIterator / CallbackFilterIterator:過濾SplFileInfo:文件元數據對象 (size, mtime, perm, isDir 等)<?php
function collectFiles($dir, array $extensions = ['php', 'html', 'css', 'js']) {
$extPattern = implode('|', array_map('preg_quote', $extensions));
$regex = "/\.($extPattern)$/i";
$files = [];
$it = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS)
);
$filter = new RegexIterator($it, $regex, RegexIterator::GET_MATCH);
foreach ($filter as $file) {
$files[] = $file->getPathname();
}
return $files;
}
$projectFiles = collectFiles('/var/www/myproject');
print_r($projectFiles);
?>
始終使用 DIRECTORY_SEPARATOR 常量而非硬編碼 / 或 \,確保跨平台兼容。
count(glob("$dir/*")) 比遍歷快。