本文目录导读:

我来为你提供几种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;
}
?>
选择哪种方法取决于你的具体需求:
- 方法一:适合需要树形结构的场景
- 方法二:性能好,适合简单遍历
- 方法三:适合可视化展示
- 方法四:适合需要过滤的场景
- 方法五:适合需要实时处理的场景