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

PHP 目錄操作四大核心功能完整實作:列表、複製、刪除、計算大小

     編輯:PHP 相關知識

前言

目錄操作是檔案系統管理的基石。本文提供四個獨立、可重複使用的函式,分別實現:遞迴列出所有檔案、遞迴複製整個目錄樹、遞迴刪除目錄、遞迴計算目錄總大小。每個函式均採用「深度優先遞迴」模式,程式碼簡潔並附詳細註解。

1. 遞迴列出所有檔案 listDir()

<?php
/**
 * 遞迴列出目錄下所有檔案(不含目錄本身)
 * @param string $dir 目錄路徑
 * @param array  $result 參考傳遞收集結果
 * @return array 檔案相對路徑陣列
 */
function listDir(string $dir, array &$result = []): array {
    $ds = opendir($dir);
    while (($file = readdir($ds)) !== false) {
        if ($file === '.' || $file === '..') continue;
        $path = $dir . DIRECTORY_SEPARATOR . $file;
        if (is_dir($path)) {
            listDir($path, $result); // 遞迴進入子目錄
        } else {
            // 可選:回傳相對路徑而非絕對路徑
            $result[] = substr($path, strlen($dir) + 1);
        }
    }
    closedir($ds);
    return $result;
}

// 使用
$files = listDir(__DIR__ . '/storage');
print_r($files);
/* 輸出範例:
Array
(
    [0] => logs/app.log
    [1] => uploads/image.png
    [2] => config/database.php
)
*/

2. 遞迴複製目錄 copyDir()

<?php
/**
 * 遞迴複製整個目錄樹
 * @param string $src 來源目錄
 * @param string $dst 目標目錄(不存在會自動建立)
 * @param bool   $overwrite 是否覆蓋同名檔案
 * @return bool
 */
function copyDir(string $src, string $dst, bool $overwrite = true): bool {
    if (!is_dir($src)) return false;
    
    if (!is_dir($dst)) {
        if (!mkdir($dst, 0755, true)) return false; // 遞迴建立目標目錄
    }
    
    $ds = opendir($src);
    while (($file = readdir($ds)) !== false) {
        if ($file === '.' || $file === '..') continue;
        $srcPath = $src . DIRECTORY_SEPARATOR . $file;
        $dstPath = $dst . DIRECTORY_SEPARATOR . $file;
        
        if (is_dir($srcPath)) {
            if (!copyDir($srcPath, $dstPath, $overwrite)) return false;
        } else {
            if ($overwrite || !file_exists($dstPath)) {
                if (!copy($srcPath, $dstPath)) return false;
                // 保留檔案權限與修改時間
                $stat = stat($srcPath);
                chmod($dstPath, $stat['mode'] & 0777);
                touch($dstPath, $stat['mtime']);
            }
        }
    }
    closedir($ds);
    return true;
}

// 使用
copyDir(__DIR__ . '/source', __DIR__ . '/backup_' . date('Ymd'));

3. 遞迴刪除目錄 deleteDir()

<?php
/**
 * 遞迴刪除目錄及其所有內容
 * @param string $dir 目錄路徑
 * @return bool
 */
function deleteDir(string $dir): bool {
    if (!is_dir($dir)) return false;
    
    $ds = opendir($dir);
    while (($file = readdir($ds)) !== false) {
        if ($file === '.' || $file === '..') continue;
        $path = $dir . DIRECTORY_SEPARATOR . $file;
        if (is_dir($path)) {
            deleteDir($path); // 先刪除子目錄
        } else {
            unlink($path);    // 再刪除檔案
        }
    }
    closedir($ds);
    return rmdir($dir); // 最後刪除空目錄本身
}

// 使用
deleteDir(__DIR__ . '/temp_cache');

4. 遞迴計算目錄大小 dirSize()

<?php
/**
 * 遞迴計算目錄總大小(位元組)
 * @param string $dir 目錄路徑
 * @return int 總位元組數
 */
function dirSize(string $dir): int {
    $total = 0;
    $ds = opendir($dir);
    while (($file = readdir($ds)) !== false) {
        if ($file === '.' || $file === '..') continue;
        $path = $dir . DIRECTORY_SEPARATOR . $file;
        if (is_dir($path)) {
            $total += dirSize($path); // 累加子目錄大小
        } else {
            $total += filesize($path); // 累加檔案大小
        }
    }
    closedir($ds);
    return $total;
}

// 使用
$bytes = dirSize(__DIR__ . '/uploads');
echo "總大小:" . formatBytes($bytes); // 需配合上一篇的 formatBytes()

function formatBytes(int $bytes, int $precision = 2): string {
    $units = ['B', 'KB', 'MB', 'GB', 'TB'];
    $pow = $bytes > 0 ? floor(log($bytes, 1024)) : 0;
    $pow = min($pow, count($units) - 1);
    return round($bytes / (1024 ** $pow), $precision) . ' ' . $units[$pow];
}

遞迴模式比較:深度優先 vs 廣度優先

特性深度優先(本文採用)廣度優先(佇列實作)
程式碼複雜度低(自然遞迴)中(需顯式佇列/堆疊)
記憶體使用呼叫堆疊深度 = 樹高佇列大寬度 = 最大層級節點數
適用場景目錄樹通常較深不寬極寬目錄結構(如百萬檔案單層)
中斷恢復困難容易(可序列化佇列)

現代化替代方案:SPL 迭代器

PHP 5.3+ 內建 RecursiveDirectoryIterator + RecursiveIteratorIterator,可用更優雅的方式實現相同功能:

// 列出所有檔案
$iterator = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS)
);
foreach ($iterator as $file) {
    if ($file->isFile()) echo $file->getPathname() . "\n";
}

// 計算大小
$size = 0;
foreach ($iterator as $file) {
    if ($file->isFile()) $size += $file->getSize();
}

優點:自動處理遞迴、支援過濾器、可直接搭配 RegexIterator 過濾副檔名。
缺點:對符號連結、權限錯誤的處理需額外 try-catch,效能略低於原生遞迴函式。

結語

掌握「開啟目錄 → 讀取項目 → 判斷類型 → 遞迴或處理 → 關閉目錄」這個經典遞迴模板,即可輕鬆應對列表、複製、刪除、計算大小等所有目錄操作需求。建議將這四個函式封裝為 Filesystem 服務類別,並加入 例外處理、進度回呼、乾跑模式,即可滿足企業級部署腳本、備份工具、同步程式的開發需求。

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