PHP目录遍历递归实现

wen PHP项目 4

本文目录导读:

PHP目录遍历递归实现

  1. 方法一:递归函数实现
  2. 方法二:使用RecursiveIteratorIterator
  3. 方法三:带格式化的树形结构
  4. 方法四:过滤特定文件的遍历
  5. 方法五:异步/回调函数实现
  6. 性能优化建议

我来为你提供几种PHP目录遍历递归实现的方法:

递归函数实现

<?php
/**
 * 递归遍历目录
 * @param string $dir 目录路径
 * @param array &$result 存储结果
 * @return array
 */
function scanDirRecursive($dir, &$result = []) {
    // 检查目录是否存在
    if (!is_dir($dir)) {
        return $result;
    }
    // 扫描目录
    $files = scandir($dir);
    foreach ($files as $file) {
        // 跳过 . 和 ..
        if ($file == '.' || $file == '..') {
            continue;
        }
        // 完整路径
        $path = $dir . '/' . $file;
        // 如果是目录,递归遍历
        if (is_dir($path)) {
            $result[] = [
                'type' => 'dir',
                'name' => $file,
                'path' => $path,
                'children' => []
            ];
            // 递归
            $index = count($result) - 1;
            scanDirRecursive($path, $result[$index]['children']);
        } else {
            // 文件
            $result[] = [
                'type' => 'file',
                'name' => $file,
                'path' => $path,
                'size' => filesize($path),
                'ext' => pathinfo($path, PATHINFO_EXTENSION)
            ];
        }
    }
    return $result;
}
// 使用方法
$files = scanDirRecursive('/path/to/directory');
echo "<pre>";
print_r($files);
echo "</pre>";
?>

使用RecursiveIteratorIterator

<?php
/**
 * 使用SPL递归迭代器
 * @param string $dir 目录路径
 * @return array
 */
function scanDirWithIterator($dir) {
    $result = [];
    if (!is_dir($dir)) {
        return $result;
    }
    // 创建递归目录迭代器
    $iterator = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dir, 
            FilesystemIterator::SKIP_DOTS | FilesystemIterator::UNIX_PATHS
        ),
        RecursiveIteratorIterator::SELF_FIRST
    );
    foreach ($iterator as $item) {
        $entry = [
            'name' => $item->getFilename(),
            'path' => $item->getPathname(),
            'type' => $item->isDir() ? 'dir' : 'file'
        ];
        // 如果是文件,添加文件信息
        if ($item->isFile()) {
            $entry['size'] = $item->getSize();
            $entry['ext'] = $item->getExtension();
        }
        $result[] = $entry;
    }
    return $result;
}
// 使用方法
$files = scanDirWithIterator('/path/to/directory');
?>

带格式化的树形结构

<?php
/**
 * 获取目录树形结构
 * @param string $dir 目录路径
 * @param int $level 层级(内部使用)
 * @return string
 */
function getDirectoryTree($dir, $level = 0) {
    static $tree = '';
    if (!is_dir($dir)) {
        return $tree;
    }
    // 获取目录内容
    $items = scandir($dir);
    foreach ($items as $item) {
        if ($item == '.' || $item == '..') {
            continue;
        }
        $path = $dir . '/' . $item;
        $indent = str_repeat('    ', $level);
        if (is_dir($path)) {
            $tree .= $indent . "📁 {$item}/\n";
            getDirectoryTree($path, $level + 1);
        } else {
            $size = formatFileSize(filesize($path));
            $tree .= $indent . "📄 {$item} ({$size})\n";
        }
    }
    return $tree;
}
/**
 * 格式化文件大小
 * @param int $bytes
 * @return string
 */
function formatFileSize($bytes) {
    if ($bytes >= 1073741824) {
        return round($bytes / 1073741824, 2) . ' GB';
    } elseif ($bytes >= 1048576) {
        return round($bytes / 1048576, 2) . ' MB';
    } elseif ($bytes >= 1024) {
        return round($bytes / 1024, 2) . ' KB';
    } else {
        return $bytes . ' B';
    }
}
// 使用方法
echo getDirectoryTree('/path/to/directory');
?>

过滤特定文件的遍历

<?php
/**
 * 递归遍历并过滤文件
 * @param string $dir 目录
 * @param array $extensions 允许的文件扩展名
 * @param bool $includeHidden 是否包含隐藏文件
 * @return array
 */
function scanDirWithFilter($dir, $extensions = [], $includeHidden = false) {
    $result = [];
    if (!is_dir($dir)) {
        return $result;
    }
    $items = scandir($dir);
    foreach ($items as $item) {
        // 过滤隐藏文件
        if (!$includeHidden && substr($item, 0, 1) == '.') {
            continue;
        }
        if ($item == '.' || $item == '..') {
            continue;
        }
        $path = $dir . '/' . $item;
        if (is_dir($path)) {
            // 递归处理子目录
            $subFiles = scanDirWithFilter($path, $extensions, $includeHidden);
            if (!empty($subFiles)) {
                $result[$item] = $subFiles;
            }
        } else {
            // 文件扩展名过滤
            $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
            if (empty($extensions) || in_array($ext, $extensions)) {
                $result[] = $path;
            }
        }
    }
    return $result;
}
// 使用示例:只获取php和html文件
$files = scanDirWithFilter('/path/to/directory', ['php', 'html'], true);
print_r($files);
?>

异步/回调函数实现

<?php
/**
 * 使用回调函数处理每个文件
 * @param string $dir 目录
 * @param callable $callback 回调函数
 * @return void
 */
function traverseDirectory($dir, $callback) {
    if (!is_dir($dir)) {
        return;
    }
    $items = scandir($dir);
    foreach ($items as $item) {
        if ($item == '.' || $item == '..') {
            continue;
        }
        $path = $dir . '/' . $item;
        if (is_dir($path)) {
            // 调用回调函数处理目录
            call_user_func($callback, $path, 'dir');
            // 递归处理子目录
            traverseDirectory($path, $callback);
        } else {
            // 调用回调函数处理文件
            call_user_func($callback, $path, 'file');
        }
    }
}
// 使用示例
$totalSize = 0;
$fileCount = 0;
traverseDirectory('/path/to/directory', function($path, $type) use (&$totalSize, &$fileCount) {
    if ($type == 'file') {
        $totalSize += filesize($path);
        $fileCount++;
        echo "文件: {$path} (" . formatFileSize(filesize($path)) . ")\n";
    } else {
        echo "目录: {$path}\n";
    }
});
echo "\n统计信息:\n";
echo "文件总数: {$fileCount}\n";
echo "总大小: " . formatFileSize($totalSize) . "\n";
?>

性能优化建议

<?php
/**
 * 高性能递归遍历(推荐)
 */
function scanDirEfficient($dir) {
    $result = [];
    // 使用FilesystemIterator性能更好
    $iterator = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dir, 
            FilesystemIterator::SKIP_DOTS | FilesystemIterator::QUERY_WHERE
        )
    );
    foreach ($iterator as $file) {
        if ($file->isFile()) {
            $result[] = [
                'path' => $file->getPathname(),
                'filename' => $file->getFilename(),
                'size' => $file->getSize(),
                'modified' => date('Y-m-d H:i:s', $file->getMTime())
            ];
        }
    }
    return $result;
}
?>

选择哪种方法取决于你的具体需求:

  • 方法一:适合需要树形结构的场景
  • 方法二:性能好,适合简单遍历
  • 方法三:适合可视化展示
  • 方法四:适合需要过滤的场景
  • 方法五:适合需要实时处理的场景

抱歉,评论功能暂时关闭!