如何使用 PHP 正确重命名文件夹中最新修改的文件

本文详解如何通过 glob() 结合 usort() 和 filemtime() 精准定位并重命名指定目录下最新修改的文件,避免 scandir() 仅按名称排序导致的逻辑错误,并提供安全可靠的正则替换与路径处理方案。

在 PHP 中,仅依赖 scandir() 按字典序降序排列(如 SCANDIR_SORT_DESCENDING)并不能保证获取“最新添加/修改”的文件——因为文件名(如 file_0202.json)的字母顺序与实际时间顺序无关。正确做法是基于文件系统元数据(如最后修改时间)进行排序。

以下为推荐实现方案:

 filemtime($a); // PHP 7+ 太空船操作符,简洁安全
});

$selected_file = $files[0];
$dir_path = dirname($selected_file);
$basename = basename($selected_file);

// 3. 安全地构造新文件名:仅替换文件名中的下划线编号部分,不触碰路径
$new_basename = preg_replace('/^([^_]+)_([^_.]*)\.([^.]+)$/', '$1.$3', $basename);
$new_filepath = $dir_path . '/' . $new_basename;

// 4. 执行重命名(注意:源和目标必须在同一文件系统,且目标不可存在)
if (rename($selected_file, $new_filepath)) {
    echo "Renamed successfully: {$basename} → {$new_basename}";
} else {
    echo "Failed to rename: " . error_get_last()['message'] ?? 'Unknown error';
}
?>

关键改进说明

  • 使用 glob() 返回带路径的完整文件名,避免 scandir() 返回相对名后 rename() 因路径缺失而失败;
  • usort() + filemtime() 确保按真实修改时间排序,而非文件名字符串;
  • 正则 /^([^_]+)_([^_.]*)\.([^.]+)$/ 更精准:捕获主名、下划线后编号、扩展名三部分,仅替换中间编号段,防止误改路径或嵌套下划线(如 data_v2_backup_01.json);
  • 显式拼接 $dir_path . '/' . $new_basename,确保目标路径有效;
  • 增加空文件检查与错误提示,提升健壮性。

⚠️ 注意事项

  • rename() 要求源与目标位于同一挂载点(同文件系统),跨分区需用 copy() + unlink();
  • 目标文件若已存在,rename() 将失败(PHP 不自动覆盖),建议提前 if (file_exists($new_filepath)) unlink($new_filepath);;
  • 生产环境应校验 $selected_file 是否为真实文件(is_file())、是否可读写(is_writable());
  • 若需按“创建时间”排序(Windows 支持,Linux 通常不保留),可用 filectime() 替代 filemtime(),但兼容性更低。

掌握此模式后,你可轻松扩展为批量处理最新 N 个文件、按时间窗口筛选或集成到定时任务中。