preg_replace用于构造新文件名而非直接重命名,真实重命名需配合rename();关键步骤包括pathinfo拆解路径、正则匹配数字序号、sprintf补零、scandir+usort排序、file_exists检查及Windows编码转换。

PHP中用 preg_replace 批量重命名带数字序号的文件
直接用 preg_replace 处理文件名字符串最稳妥,不碰磁盘,适合预处理或生成新名称。关键不是“替换文件”,而是“构造新文件名”——真实重命名得靠 rename() 配合使用。
- 匹配数字序号常用模式:
/\d+/(任意连续数字),/\d{3}/(固定3位),或更安全的/_(\d+)\./(匹配下划线后、点前的数字) - 替换时注意保留扩展名:先用
pathinfo()拆解原路径,避免把.jpg误替成.new.jpg - 若需补零(如
img1.jpg→img001.jpg),用sprintf('%03d', $num)而非硬写'00'.$num,否则10会变0010
$old = 'photo_5.jpg';
$info = pathinfo($old);
$base = $info['filename'];
$ext = $info['extension'];
// 将 _5 → _005
$new_base = preg_replace('/_(\d+)/', '_'.sprintf('%03d', $1), $base);
$new_name = $new_base . '.' . $ext; // photo_005.jpg
用 scandir() + rename() 批量处理目录下序列文件
真正改文件名必须调用 rename(),且需确保目标路径不存在、有写权限。别跳过 file_exists() 检查,否则同名覆盖静默失败。
-
scandir()返回包含.和..的数组,务必用array_diff()过滤 - 按数字序号排序再处理:用
usort()+preg_match()提取数字,避免img10.jpg排在img2.jpg前面 - 重命名前加
is_writable(dirname($target))判断,Linux 下常因权限拒绝报Warning: rename(): Permission denied
$dir = '/path/to/images/';
$files = array_diff(scandir($dir), ['.', '..']);
usort($files, function($a, $b) {
preg_match('/(\d+)/', $a, $ma);
preg_match('/(\d+)/', $b, $mb);
return ($ma[1] ?? 0) <=> ($mb[1] ?? 0);
});
foreach ($files as $i => $file) {
$old_path = $dir . $file;
$info = pathinfo($file);
$new_name = sprintf('pic_%04d.%s', $i + 1, $info['extension']);
$new_path = $dir . $new_name;
if (!file_exists($new_path)) {
rename($old_path, $new_path);
}
}
遇到 rename(): File exists 错误怎么绕过
这不是 PHP Bug,是目标文件已存在。常见于循环中未清空旧序号、或两次运行脚本没清理中间状态。
- 强制覆盖:用
unlink($new_path)先删目标(仅限确定可丢弃旧文件) - 跳过冲突:加
continue并记录日志,避免中断整个批量流程 - 更安全做法:生成临时唯一名(如加时间戳后缀),再用
rename()覆盖,防止并发写入冲突
Windows 下中文文件名乱码导致 rename() 失败
PHP 本身不自动处理 Windows 控制台的 GBK 编码,scandir() 读出的中文名是 UTF-8 字节流,但系统 API 期望 GBK —— 表现为文件名显示为 ?????.jpg 或操作失败。
立即学习“PHP免费学习笔记(深入)”;
- 临时方案:用
iconv('UTF-8', 'GBK', $filename)转换后再传给rename() - 根本解法:在 PHP 启动时加
ini_set('default_charset', 'GBK'),或统一用mb_convert_encoding()处理路径 - 验证是否生效:用
var_dump(bin2hex($filename))看字节是否符合预期编码
preg_replace 构造逻辑,再加 rename(),最后补上错误分支和日志,比一上来就扫整个目录更可控。











