opendir()、readdir()、closedir() 是 PHP 檔案系統操作的基礎組合,用於開啟目錄句柄、逐項讀取、關閉釋放資源。本文詳細說明語法、參數、常見模式與進階替代方案 (SPL)。
<?php
$dir = "./"; // 目標目錄
// 1. 開啟目錄句柄
if (is_dir($dir)) {
if ($dh = opendir($dir)) {
// 2. 迴圈讀取每一項
while (($file = readdir($dh)) !== false) {
// $file 僅為檔名,需拼接完整路徑才能用 filetype(), filesize() 等
$fullPath = $dir . $file;
echo "檔名: $file | 類型: " . filetype($fullPath) . "
";
}
// 3. 關閉句柄 (重要!釋放系統資源)
closedir($dh);
} else {
echo "無法開啟目錄: $dir";
}
} else {
echo "路徑不是目錄: $dir";
}
?>
| 函數 | 說明 | 回傳值 |
|---|---|---|
opendir(path, context) | 開啟目錄句柄。context 可選,用於流上下文 (如 FTP、HTTP 協議)。 | 資源 handle 或 false |
readdir(handle) | 讀取目錄下一項 (含 . ..)。 | 檔名字串或 false (結束) |
closedir(handle) | 關閉目錄句柄。 | bool |
rewinddir(handle) | 將指標重置到目錄開頭。 | void |
scandir(path) | 一次性讀取整個目錄到陣列 (內建排序),簡單場合更方便。 | 陣列 |
<?php
function listDirRecursive($path, $indent = '') {
$dh = @opendir($path);
if (!$dh) return;
while (($file = readdir($dh)) !== false) {
if ($file === '.' || $file === '..') continue;
$full = $path . DIRECTORY_SEPARATOR . $file;
if (is_dir($full)) {
echo $indent . "📁 $file
";
listDirRecursive($full, $indent . ' ');
} else {
echo $indent . "📄 $file
";
}
}
closedir($dh);
}
listDirRecursive(__DIR__);
?>
RecursiveDirectoryIterator + RecursiveIteratorIterator 提供物件導向、記憶體高效、可過濾、可排序的遍歷能力。
<?php
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(__DIR__, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
);
// 只列出 .php 檔案,按大小降序
$files = new RegexIterator($iterator, '/\.php$/i');
$files = new ArrayIterator(iterator_to_array($files));
$files->uasort(function($a, $b) { return $b->getSize() <=> $a->getSize(); });
foreach ($files as $file) {
printf("%s (%s)
", $file->getPathname(), formatBytes($file->getSize()));
}
function formatBytes($bytes) {
$units = ['B','KB','MB','GB'];
$i = $bytes > 0 ? floor(log($bytes, 1024)) : 0;
return round($bytes / (1024 ** $i), 2) . ' ' . $units[$i];
}
?>
iconv('GBK', 'UTF-8', $file) 轉碼後再輸出或操作。opendir 失敗會觸發 Warning,建議用 @opendir 配合 error_get_last() 或 is_readable() 預檢。scandir 佔用大量記憶體,readdir 迴圈或 SPL 迭代器更省記憶體。closedir(),長時間運行腳本 (如守護進程) 未關閉會耗盡檔案描述符。is_dir() 會跟隨連結,遞迴時需用 is_link() 判斷並決定是否進入,避免無限迴圈。掌握 opendir 系列函數是 PHP 檔案系統操作的入門基石,實務上建議優先使用 SPL 迭代器獲得更健壯、可維護的代碼。