項目遷移、框架升級、統一代碼風格時,常需將目錄下特定後綴文件批量重命名(如 .c → .txt、.html → .blade.php)。
/**
* 遞歸批量修改文件後綴
*
* @param string $path 目錄路徑(結尾不帶斜槓)
* @param string $srcExt 源後綴(不帶點),'all' 表示全部文件
* @param string $dstExt 目標後綴(不帶點)
* @return void
*/
function batchRenameExt(string $path, string $srcExt, string $dstExt): void
{
$path = rtrim($path, DIRECTORY_SEPARATOR);
if (!is_dir($path)) {
throw new InvalidArgumentException("目錄不存在:$path");
}
$handle = opendir($path);
if (!$handle) return;
while (($file = readdir($handle)) !== false) {
if ($file === '.' || $file === '..') continue;
$fullPath = $path . DIRECTORY_SEPARATOR . $file;
if (is_dir($fullPath)) {
// 遞歸處理子目錄
batchRenameExt($fullPath, $srcExt, $dstExt);
continue;
}
// 獲取文件後綴
$dotPos = strrpos($file, '.');
if ($dotPos === false) continue; // 無後綴跳過
$currentExt = substr($file, $dotPos + 1);
$fileName = substr($file, 0, $dotPos);
// 匹配源後綴
if ($srcExt !== 'all' && strtolower($currentExt) !== strtolower($srcExt)) {
continue;
}
$newName = $fileName . '.' . $dstExt;
$newPath = $path . DIRECTORY_SEPARATOR . $newName;
// 避免覆蓋同名文件
if (file_exists($newPath)) {
echo "⚠️ 跳過:目標文件已存在 - $newPath" . PHP_EOL;
continue;
}
if (rename($fullPath, $newPath)) {
echo "✅ $file → $newName" . PHP_EOL;
} else {
echo "❌ 重命名失敗:$file" . PHP_EOL;
}
}
closedir($handle);
}
// 將 D:\project\src 下所有 .c 改為 .txt
batchRenameExt('D:\project\src', 'c', 'txt');
// 將所有文件(不管後綴)改為 .bak
batchRenameExt('D:\backup', 'all', 'bak');
| 功能 | 實現思路 |
|---|---|
| 乾運行模式 | 加參數 $dryRun = true,只打印不執行 rename |
| 大小寫不敏感 | strtolower() 比較後綴(已在代碼中體現) |
| 排除目錄 | 傳入 $excludeDirs = ['.git', 'vendor', 'node_modules'] |
| 進度條 | CLI 下用 cli-progress-bar 或簡單計數輸出 |
| 撤銷功能 | 記錄 [$oldPath => $newPath] 到日誌文件,提供 rollback() |
use Symfony\Component\Finder\Finder;
use Symfony\Component\Filesystem\Filesystem;
$finder = Finder::create()
->files()
->in('/path/to/dir')
->name('*.c');
$fs = new Filesystem();
foreach ($finder as $file) {
$newPath = $file->getPath() . '/' . $file->getBasename('.c') . '.txt';
$fs->rename($file->getRealPath(), $newPath);
}
優點:鏈式 API、自動處理跨平台路徑、支援過濾器、可組合。缺點:需 Composer 安裝依賴。
批量重命名看似簡單,實則涉及遞歸遍歷、路徑拼接、編碼兼容、覆蓋保護等細節。封裝成可復用函數或引入成熟組件,能讓這類運維操作安全、可控、可審計。下次再手改後綴時,請跑個腳本吧!