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

PHP 遞歸遍歷目錄獲取所有文件與子目錄完整代碼

     編輯:PHP 相關知識

掃描目錄樹、構建文件索引、批量處理文件時,需遞歸獲取所有文件及子目錄路徑。本文提供標準遞歸函數、SPL 迭代器現代寫法、生成器版 (內存友好)、常見過濾需求擴展。

方案一:標準遞歸函數 (兼容性最好)

<?php
/**
 * 遞歸讀取目錄所有文件與子目錄
 * @param string $dir 絕對路徑
 * @return array ['dir' => [路徑=>子樹], 'file' => [文件路徑...]]
 */
function readAllDir(string $dir): array {
    $result = ['dir' => [], 'file' => []];
    $handle = @opendir($dir);
    if (!$handle) return $result;

    while (($file = readdir($handle)) !== false) {
        if ($file === '.' || $file === '..') continue;
        $path = $dir . DIRECTORY_SEPARATOR . $file;
        if (is_dir($path)) {
            $result['dir'][$path] = readAllDir($path); // 遞歸
        } else {
            $result['file'][] = $path;
        }
    }
    closedir($handle);
    return $result;
}

// 使用
$tree = readAllDir('/var/www/project');
print_r($tree);
/*
Array
(
    [dir] => Array
        (
            [/var/www/project/app] => Array
                (
                    [dir] => Array(...)
                    [file] => Array([0] => /var/www/project/app/config.php, ...)
                )
        )
    [file] => Array
        (
            [0] => /var/www/project/index.php
            ...
        )
)
*/
?>

方案二:SPL RecursiveDirectoryIterator (現代、面向對象)

<?php
function getAllFilesSpl(string $dir): array {
    $files = [];
    $dirs  = [];
    $iterator = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS),
        RecursiveIteratorIterator::SELF_FIRST // 先返回目錄再文件
    );

    foreach ($iterator as $path => $info) {
        if ($info->isDir()) {
            $dirs[] = $path;
        } else {
            $files[] = $path;
        }
    }
    return ['dir' => $dirs, 'file' => $files];
}

// 只獲取文件 (最常用)
function getFilesOnly(string $dir): array {
    $files = [];
    $iterator = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS)
    );
    foreach ($iterator as $info) {
        if ($info->isFile()) $files[] = $info->getPathname();
    }
    return $files;
}
?>

方案三:生成器版 (大目錄樹內存友好)

<?php
/**
 * 生成器逐個產出文件路徑,不一次性載入所有路徑到內存
 */
function yieldFiles(string $dir): Generator {
    $iterator = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS)
    );
    foreach ($iterator as $info) {
        if ($info->isFile()) {
            yield $info->getPathname();
        }
    }
}

// 使用:逐個處理,內存常數級
foreach (yieldFiles('/var/www/huge_project') as $file) {
    // 處理單個文件 (解析、壓縮、上傳...)
    if (pathinfo($file, PATHINFO_EXTENSION) === 'php') {
        // do something
    }
}
?>

常見過濾擴展 (在生成器/迭代器中加入)

<?php
function getFilteredFiles(string $dir, array $exts = ['php', 'html', 'css', 'js']): array {
    $exts = array_map('strtolower', $exts);
    $files = [];
    $iterator = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS)
    );
    foreach ($iterator as $info) {
        if ($info->isFile()) {
            $ext = strtolower($info->getExtension());
            if (in_array($ext, $exts, true)) {
                $files[] = $info->getPathname();
            }
        }
    }
    return $files;
}

// 過濾隱藏文件/目錄 (以 . 開頭)
$iterator = new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS);
// SKIP_DOTS 已跳過 . 和 ..,但不跳過 .git、.env 等
// 需額外判斷
if ($info->isFile() && $info->getBasename()[0] !== '.') { ... }
?>

性能與選擇建議

方案優點缺點適用場景
遞歸函數無依賴、邏輯可控、返回結構化樹深層目錄可能棧溢出、大樹內存佔用高中小目錄、需樹結構
SPL 迭代器標準庫、面向對象、支持過濾器鏈返回扁平列表、需額外構建樹通用掃描、生產環境首選
生成器**內存 O(1)**、可中斷、流式處理不可隨機訪問、無法直接獲取總數**超大目錄 (10萬+ 文件)、批量處理管道**

實戰:構建文件修改時間索引 (生成器版)

<?php
function buildMtimeIndex(string $dir): Generator {
    $iterator = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS)
    );
    foreach ($iterator as $info) {
        if ($info->isFile()) {
            yield $info->getPathname() => $info->getMTime();
        }
    }
}

// 使用: 找出 24 小時內修改的文件
$recent = [];
$cutoff = time() - 86400;
foreach (buildMtimeIndex('/var/www/project') as $file => $mtime) {
    if ($mtime > $cutoff) $recent[] = $file;
}
print_r($recent);
?>
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved