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

PHP opendir() 遍歷目錄完整指南:遞歸掃描、過濾、SPL 現代化方案

     編輯:PHP 綜合知識

前言

opendir()、readdir()、closedir() 是 PHP 經典目錄操作三件套。本文從基礎用法進階到遞歸掃描、文件過濾,並介紹現代 SPL 迭代器替代方案。

基礎用法:列出單級目錄文件

 . [1] => .. [2] => file1.txt [3] => dir1 ... )

進階:過濾 . 和 ..,輸出 HTML 列表

$file";
    }
}
closedir($dir);
?>

目錄文件列表

Files in

實戰:遞歸掃描所有子目錄(返回完整路徑)

function scanDirRecursive($path, &$result = []) {
    $handle = @opendir($path);
    if (!$handle) return $result;

    while (($file = readdir($handle)) !== false) {
        if ($file === '.' || $file === '..') continue;
        $fullPath = $path . DIRECTORY_SEPARATOR . $file;
        if (is_dir($fullPath)) {
            scanDirRecursive($fullPath, $result);
        } else {
            $result[] = $fullPath;
        }
    }
    closedir($handle);
    return $result;
}

$allFiles = scanDirRecursive('/var/www/html');
print_r($allFiles);

現代化方案:SPL 迭代器(推薦)

PHP 5.3+ 提供 RecursiveDirectoryIterator + RecursiveIteratorIterator,代碼更簡潔、功能更強:

// 1. 遞歸遍歷所有文件(含子目錄)
$iterator = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator('/var/www/html', 
        RecursiveDirectoryIterator::SKIP_DOTS) // 自動跳過 . 和 ..
);

foreach ($iterator as $file) {
    if ($file->isFile()) {
        echo $file->getPathname() . " ({$file->getSize()} bytes)\n";
    }
}

// 2. 只獲取特定擴展名文件
$filter = new RegexIterator(
    new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator('/var/www/html', RecursiveDirectoryIterator::SKIP_DOTS)
    ),
    '/\.php$/i'
);
foreach ($filter as $file) {
    echo $file->getPathname() . "\n";
}

// 3. 限制深度
$iterator = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator('/var/www/html', RecursiveDirectoryIterator::SKIP_DOTS),
    RecursiveIteratorIterator::SELF_FIRST
);
$iterator->setMaxDepth(2); // 只掃描 2 層
foreach ($iterator as $file) {
    echo str_repeat('  ', $iterator->getDepth()) . $file->getFilename() . "\n";
}

常見需求封裝:獲取目錄結構樹

function getDirTree($path) {
    $tree = ['name' => basename($path), 'path' => $path, 'type' => 'dir', 'children' => []];
    $iterator = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS),
        RecursiveIteratorIterator::SELF_FIRST
    );

    $pathMap = [$path => &$tree];
    foreach ($iterator as $item) {
        $parentPath = $item->getPath();
        $currentPath = $item->getPathname();
        $name = $item->getFilename();

        if (!isset($pathMap[$parentPath])) continue;

        $node = [
            'name' => $name,
            'path' => $currentPath,
            'type' => $item->isDir() ? 'dir' : 'file',
            'size' => $item->isFile() ? $item->getSize() : 0,
            'mtime' => $item->getMTime(),
            'children' => []
        ];

        $pathMap[$parentPath]['children'][] = $node;
        if ($item->isDir()) {
            $pathMap[$currentPath] = &$pathMap[$parentPath]['children'][array_key_last($pathMap[$parentPath]['children'])];
        }
    }
    return $tree;
}

$tree = getDirTree('/var/www/html');
echo json_encode($tree, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);

效能與記憶體對比

方案記憶體速度功能豐富度推薦
opendir + 遞歸函數低(流式)快基礎舊版本兼容
scandir()高(全載入陣列)快基礎簡單場景
SPL RecursiveIterator低(迭代器模式)快極高(過濾、深度、鍵值訪問)★★★★★ 現代首選
glob()中中模式匹配特定模式

常見坑位避雷

  • 權限問題:opendir 失敗返回 false,需 @ 抑制警告並判斷。
  • Windows 路徑分隔符:統一用 DIRECTORY_SEPARATOR 或正斜杠 /(PHP 支援)。
  • 符號鏈接循環:SPL 預設跟隨符號鏈接,可能陷入死循環,需自行檢測 $file->isLink() 並記錄已訪問 inode。
  • 大目錄性能:萬級文件目錄下 scandir 記憶體飆升,必須用迭代器流式處理。

結語

掌握 opendir 經典三件套是基礎,但現代 PHP 專案請直接使用 SPL 迭代器,代碼更健壯、功能更強、記憶體更友好。封裝通用 DirScanner 服務類,統一項目中所有目錄操作。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved