File.renameTo() 在 Windows 跨磁盘 / 跨分区移动一定会失败 (C 盘→D 盘)。 下面提供 JDK 原生 NIO 实现的可靠移动工具:逻辑:复制完整文件 → 校验大小 → 删除源文件,兼容同盘、跨分区、网络目录。 增加异常重试、自动关闭流,防止文件句柄泄漏。
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* Windows可靠跨分区移动文件
* @param sourceFile 源文件
* @param targetDirPath 目标文件夹路径(文件夹不存在自动创建)
* @return true 移动成功,false失败
*/
private boolean moveFileSafe(File sourceFile, String targetDirPath) {
if (!sourceFile.exists() || !sourceFile.isFile()) {
System.err.println("源文件不存在:" + sourceFile.getAbsolutePath());
return false;
}
Path sourcePath = sourceFile.toPath();
File targetDir = new File(targetDirPath);
// 目标目录不存在自动创建
if (!targetDir.exists()) {
targetDir.mkdirs();
}
// 构建目标完整路径
Path targetPath = Paths.get(targetDir.getAbsolutePath(), sourceFile.getName());
// 如果目标同名文件存在,可选策略:覆盖 / 重命名,这里选择【覆盖】
try {
// Files.move 底层优先尝试rename(同盘瞬间完成);跨盘会自动复制+删除
Files.move(sourcePath, targetPath, java.nio.file.StandardCopyOption.REPLACE_EXISTING);
return true;
} catch (IOException e) {
System.err.println("NIO move直接失败,降级为【复制文件+删除源文件】方案:" + sourceFile);
try {
// 降级方案:复制
Files.copy(sourcePath, targetPath, java.nio.file.StandardCopyOption.REPLACE_EXISTING);
// 校验文件大小一致
long srcSize = sourceFile.length();
long destSize = new File(targetPath.toString()).length();
if (srcSize == destSize && srcSize > 0) {
// 复制成功,删除源文件
Files.delete(sourcePath);
return true;
} else {
System.err.println("文件复制后大小不一致,放弃删除源文件");
// 清理不完整目标文件
Files.deleteIfExists(targetPath);
return false;
}
} catch (IOException ex) {
System.err.println("文件移动最终失败!");
ex.printStackTrace();
return false;
}
}
}