PHP 內建 filesize() 僅能取得單一檔案大小,**缺乏直接計算目錄總大小的函數**。本文示範如何以**遞迴演算法**實作 dirSize(),正確處理子目錄、排除特殊目錄、單位換算,並提供效能優化與替代方案討論。
opendir)。readdir 讀取每個條目。. 與 ..** 避免無限遞迴。$sub = $dir . '/' . $entry。is_dir($sub) → 遞迴呼叫 dirSize($sub) 累加。is_file($sub) → filesize($sub) 累加。<?php
function dirSize(string $directory): int {
$total = 0;
$handle = @opendir($directory);
if (!$handle) return 0; // 無權限或不存在視為 0
while (($entry = readdir($handle)) !== false) {
if ($entry === '.' || $entry === '..') continue;
$path = $directory . '/' . $entry;
if (is_dir($path)) {
$total += dirSize($path); // 遞迴
} elseif (is_file($path)) {
$total += filesize($path);
}
// 略過 link、socket 等特殊類型
}
closedir($handle);
return $total;
}
// 使用範例
$bytes = dirSize('phpMyAdmin');
echo '目錄大小:' . round($bytes / 1024, 2) . ' KB';
echo ' / ' . round($bytes / 1024 / 1024, 2) . ' MB';
?>
function dirSizeAdvanced(string $dir, array $options = []): int {
static $cache = []; // 簡易記憶體快取,避免同目錄重複計算
$key = realpath($dir);
if ($key && isset($cache[$key])) return $cache[$key];
$exclude = $options['exclude'] ?? ['.git', 'node_modules', 'vendor', 'storage/logs'];
$followLinks = $options['follow_links'] ?? false;
$total = 0;
$handle = @opendir($dir);
if (!$handle) return 0;
while (($entry = readdir($handle)) !== false) {
if ($entry === '.' || $entry === '..') continue;
if (in_array($entry, $exclude, true)) continue;
$path = $dir . '/' . $entry;
if (is_link($path)) {
if (!$followLinks) continue;
$path = readlink($path); // 解析連結實際路徑
}
if (is_dir($path)) {
$total += dirSizeAdvanced($path, $options);
} elseif (is_file($path)) {
$sz = @filesize($path);
if ($sz !== false) $total += $sz;
}
}
closedir($handle);
if ($key) $cache[$key] = $total;
return $total;
}
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| PHP 遞迴 (本文) | 純 PHP、跨平台、可自訂邏輯 | 大量檔案/深層目錄效能較差、受 max_execution_time 限制 | 中小型專案、需自訂排除規則 |
exec('du -sh ...') | 極快、系統級優化 | 需 exec 權限、僅 Linux/Unix、安全風險、跨平台差 | 內部管理工具、Linux 伺服器環境 |
SPL RecursiveDirectoryIterator | 物件導向、可搭配 FilterIterator | 記憶體佔用較大、速度略慢於原生函數 | 現代框架專案、需複雜過濾 |
opendir/filesize 可能因權限回傳 false,務必用 @ 抑制警告並檢查回傳值。is_link(),決定是否跟隨或略過。formatBytes($bytes, $precision=2) 統一輸出 KB/MB/GB/TB。掌握遞迴目錄大小計算,能為檔案管理面板、備份系統、磁碟配額監控等功能提供核心資料支撐。