统计一个目录占了多少空间、有多少文件,是磁盘清理与备份任务的常见前置步骤。PHP 用 scandir 配合递归可以轻松实现,注意目录里的 . 与 .. 要跳过,否则会死循环。

完整代码

<?php
/**
 * 递归统计目录:返回 [size 字节, count 文件数]
 */
function dirStat(string $dir): array
{
    $size = 0;
    $count = 0;
    $items = scandir($dir);
    if ($items === false) {
        return ["size" => 0, "count" => 0];
    }

    foreach ($items as $item) {
        if ($item === "." || $item === "..") {
            continue;
        }
        $full = rtrim($dir, "/") . "/" . $item;
        if (is_dir($full)) {
            $sub = dirStat($full);
            $size += $sub["size"];
            $count += $sub["count"];
        } else {
            $size += filesize($full);
            $count++;
        }
    }
    return ["size" => $size, "count" => $count];
}

/**
 * 字节数格式化为可读容量
 */
function formatSize(int $bytes): string
{
    $units = ["B", "KB", "MB", "GB", "TB"];
    $i = 0;
    while ($bytes >= 1024 && $i < count($units) - 1) {
        $bytes /= 1024;
        $i++;
    }
    return round($bytes, 2) . " " . $units[$i];
}

$stat = dirStat("D:/www/site/upload");
echo "文件数:" . $stat["count"] . PHP_EOL;
echo "总大小:" . formatSize($stat["size"]) . PHP_EOL;
?>

注意事项

  • Linux 下软链接可能造成递归死循环,必要时用 is_link 拦截;
  • filesize 对超大文件返回类型注意使用 64 位 PHP,避免溢出;
  • 目录数量大时优先使用 RecursiveIteratorIterator 迭代器,内存占用更低。

小结

递归统计逻辑清晰易读,适合中小目录;需要快速展示全盘容量分布时,改为迭代器加按目录聚合更高效。