首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 遍歷目錄與文件的四種核心方法:scandir、glob、opendir、SPL 迭代器

     編輯:PHP 相關知識

方法對比總覽

方法返回值遞歸支持過濾模式性能/記憶體推薦場景
scandir()文件名數組手動遞歸無 (需自行過濾)一次性載入全部,大目錄佔記憶體小目錄、簡單列表
glob()匹配路徑數組手動遞歸通配符 + GLOB_BRACE同 scandir,但可預過濾按模式匹配文件
opendir/readdir資源句柄 → 逐個讀取手動遞歸無流式讀取,記憶體常數級超大目錄、需精細控制
RecursiveDirectoryIterator (SPL)迭代器對象內建遞歸RegexIterator 過濾延遲加載,面向對象現代框架、複雜遍歷邏輯

1. scandir() + 遞歸函數

<?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。

2. glob() 通配符匹配 + GLOB_BRACE

<?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() 自動過濾 . 和 ..。

3. opendir() / readdir() 底層流式讀取

<?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');
?>

優勢:不將所有文件名載入內存,適合百萬級文件目錄;可精細控制讀取流程 (如限制深度、並發處理)。

4. SPL 迭代器:現代標準寫法

<?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);
?>

Windows 路徑分隔符兼容

始終使用 DIRECTORY_SEPARATOR 常量而非硬編碼 / 或 \,確保跨平台兼容。

性能建議

  • 超大目錄 (>10萬文件):**必須用 opendir/readdir 或 SPL 迭代器**,避免 scandir/glob 佔滿內存。
  • 頻繁遍歷同一目錄:考慮緩存文件列表 (Redis/APCu),文件變更時通過 inotify/fsnotify 更新緩存。
  • 僅需統計數量:count(glob("$dir/*")) 比遍歷快。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved