如何使用 PHP 重命名指定目录中最新修改的文件

本文介绍如何准确识别并重命名目标文件夹中最后修改时间最晚的文件(如将 `file_0202.json` 改为 `file.json`),重点解决 `scandir()` 无法按修改时间排序、路径缺失导致 `rename()` 失败等常见问题。

在 PHP 中,仅依赖 scandir() 按字母顺序降序排列(SCANDIR_SORT_DESCENDING)并不能获取“最新添加/修改”的文件——因为文件名排序(如 file_zzz.json > file_0202.json)与实际时间戳完全无关。此外,原代码中 $selected_file = $files[0] 得到的是不含路径的纯文件名(如 file_0202.json),而 rename() 需要完整源路径完整目标路径,否则会尝试在当前脚本所在目录下查找该文件,必然失败。

正确的做法是:

  1. 使用 glob() 获取带完整路径的文件列表:确保路径上下文明确;
  2. 用 usort() + filemtime() 按最后修改时间逆序排序:filemtime($b) filemtime($a) 实现从新到旧;
  3. 安全构造新文件路径:正则替换时需限定作用范围,避免误改目录部分;
  4. 校验路径有效性并启用错误提示(可选但推荐)。

以下是优化后的完整示例代码:

 filemtime($a);
});

$latestFile = $files[0];
$dirPath    = dirname($latestFile);
$filename   = basename($latestFile);

// 安全替换:仅匹配文件名中最后一个下划线+非点非下划线字符+点(如 "_0202.")
$newBasename = preg_replace('/_[^_.]*\./', '.', $filename);
$newFilePath = $dirPath . '/' . $newBasename;

// 关键:确保源和目标均为绝对或同级相对路径
if (rename($latestFile, $newFilePath)) {
    echo "Renamed successfully: {$filename} → {$newBasename}";
} else {
    echo "Failed to rename. Error: " . error_get_last()['message'] ?? 'Unknown error';
}
?>

⚠️ 注意事项

  • 正则 /_[^_.]*\./ 中的 [^_.] 确保不跨过其他点或下划线,避免误伤类似 archive_v1.2.0.json 的版本号;
  • 若需保留原始扩展名且仅去除末尾下划线编号,也可改用更稳健的写法:preg_replace('/_\w+(?=\.[^.]+$)/', '', $filename);
  • 生产环境建议增加权限检查(is_writable($directory))和文件存在性验证(file_exists($latestFile));
  • Windows 系统对文件锁敏感,若文件正被占用,rename() 会静默失败——此时应捕获 error_get_last() 进行诊断。

通过以上方法,即可稳定、可靠地实现“重命名最新修改文件”这一典型运维需求。