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

PHP 遞歸掃描目錄查找指定大小文件:從基礎遍歷到人性化大小格式化

     編輯:PHP 綜合知識

PHP 文件系統搜索實戰:按大小篩選文件並友好顯示體積

運維、審計、清理場景常需「找出佔用空間超過 X MB 的文件」。本文從遞歸目錄遍歷入手,逐步構建完整的文件大小篩選工具,並實現智能單位轉換(B/KB/MB/GB/TB/PB)。

基礎:遞歸目錄遍歷

<?php
function tree($directory) {
    $mydir = dir($directory);
    echo "<ul>\n";
    
    while ($file = $mydir->read()) {
        if ($file === '.' || $file === '..') continue;
        
        $path = "$directory/$file";
        if (is_dir($path)) {
            echo "<li><b>$file</b></li>\n";
            tree($path);  // 遞歸
        } else {
            echo "<li>$file</li>\n";
        }
    }
    echo "</ul>\n";
    $mydir->close();
}

tree("./nowamagic");

進階:指定大小篩選 + 完整路徑輸出

<?php
header("Content-Type: text/html; charset=utf-8");
set_time_limit(0);  // 防止大目錄遍歷超時

$rootPath = __DIR__;           // 掃描根目錄
$minSize  = 1024 * 110;        // 閾值:110 KB (字節)
$results  = [];

scanLargeFiles($rootPath, $minSize, $results);

// 按大小降序排序
usort($results, fn($a, $b) => $b['size'] - $a['size']);

// 輸出結果
foreach ($results as $file) {
    $relPath = str_replace($rootPath, '', $file['path']);
    echo "<p>$relPath <br> {$file['size_human']}</p>\n";
}

function scanLargeFiles($path, $minSize, &$results) {
    $handle = @opendir($path);
    if (!$handle) return;
    
    while (false !== ($file = readdir($handle))) {
        if ($file === '.' || $file === '..') continue;
        
        $fullPath = $path . '/' . $file;
        
        if (is_dir($fullPath)) {
            scanLargeFiles($fullPath, $minSize, $results);  // 遞歸
        } elseif (is_file($fullPath)) {
            $size = filesize($fullPath);
            if ($size > $minSize) {
                $results[] = [
                    'path'        => $fullPath,
                    'size'        => $size,
                    'size_human'  => formatBytes($size)
                ];
            }
        }
    }
    closedir($handle);
}

核心工具:智能位元組格式化函數

<?php
/**
 * 位元組轉人類可讀格式 (基於 1024 進制)
 * @param int $bytes 位元組數
 * @param int $decimals 小數位數
 * @return string 如 "1.5 MB", "1024 KB"
 */
function formatBytes($bytes, $decimals = 2) {
    if ($bytes === 0) return '0 B';
    
    $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
    $base  = 1024;
    
    // 對數確定單位級數
    $exp = (int)floor(log($bytes, $base));
    $exp = min($exp, count($units) - 1);  // 防止超出數組
    
    $value = $bytes / pow($base, $exp);
    return round($value, $decimals) . ' ' . $units[$exp];
}

// 測試
echo formatBytes(1023);      // 1023 B
echo formatBytes(1024);      // 1 KB
echo formatBytes(1536000);   // 1.47 MB
echo formatBytes(1073741824); // 1 GB

生產級增強版:支援通配符、多線程、進度顯示

<?php
// find_large_files.php - 命令行工具版
#!/usr/bin/env php
<?php

$options = getopt("d:s:e:h", [
    "dir:", "size:", "exclude:", "help", "json", "parallel::"
]);

$dir     = $options['d'] ?? $options['dir'] ?? '.';
$minSize = parseSize($options['s'] ?? $options['size'] ?? '100M');
$exclude = $options['e'] ?? $options['exclude'] ?? '';
$asJson  = isset($options['json']);
$parallel = isset($options['parallel']);

function parseSize($str) {
    $str = strtoupper(trim($str));
    $unit = 1;
    if (preg_match('/^(\d+(?:\.\d+)?)\s*([KMGTPE]?)B?$/i', $str, $m)) {
        $val = (float)$m[1];
        switch ($m[2]) {
            case 'K': $unit = 1024; break;
            case 'M': $unit = 1024**2; break;
            case 'G': $unit = 1024**3; break;
            case 'T': $unit = 1024**4; break;
            case 'P': $unit = 1024**5; break;
            case 'E': $unit = 1024**6; break;
        }
        return (int)($val * $unit);
    }
    return 1024 * 1024 * 100; // 默認 100MB
}

// ... 並行掃描實現省略,使用 pcntl_fork 或 pthreads ...

// 單線程版掃描邏輯同前文 scanLargeFiles()

// 輸出
if ($asJson) {
    echo json_encode($results, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
} else {
    foreach ($results as $f) {
        echo sprintf("%-12s %s\n", $f['size_human'], $f['path']);
    }
}

使用示例

# 查找當前目錄下超過 500MB 的文件,輸出 JSON
php find_large_files.php -d . -s 500M --json

# 排除 vendor 目錄,人類可讀格式
php find_large_files.php -d /var/www -s 1G -e vendor

# 並行掃描加速(需 pcntl 擴展)
php find_large_files.php -d /data --parallel

常見陷阱與優化

問題原因解決方案
filesize() 返回 false文件超過 2GB(32位系統)或無權限使用 stat()['size'] 或升級 64位 PHP
掃描極慢大量小文件、網絡掛載點、權限遍歷排除目錄、使用 find 命令配合 exec()
內存耗盡結果集過大全部存入數組流式輸出/寫入文件/生成器 yield
符號鏈接循環鏈接指向父目錄記錄已訪問 inode、限制遞歸深度

替代方案:系統命令

對於超大規模文件系統,原生 find 性能碾壓 PHP:

# 查找 >100M 文件,按大小排序
find /path -type f -size +100M -printf "%s %p\n" | sort -rn | head -20

# 獲取目錄佔用大小
du -h --max-depth=1 /path | sort -hr

PHP 適合集成在 Web 介面、API 服務中;純運維排查首選系統工具。兩者結合,構建「Web 可視化 + 後端 find 加速」的混合方案效果最佳。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved