java 中复制文件最直接的方式是调用 files.copy() 方法,将源路径的内容写入目标路径。该方法支持通过 standardcopyoption 枚举参数来控制覆盖行为或原子性操作。如果源文件不存在或目标目录不可写,程序会抛出 ioexception。

Files.copy() 如何处理已存在的目标文件?
当目标文件已经存在时,Files.copy() 默认会拒绝操作并抛出 FileAlreadyExistsException。要允许覆盖,必须显式传入 StandardCopyOption.REPLACE_EXISTING 选项。如果不加此选项,即使目标文件为空或权限允许,复制也会失败。

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
public class FileCopier {
public static void main(String[] args) {
Path source = Paths.get("source.txt");
Path target = Paths.get("target.txt");
try {
// 尝试复制,若 target 存在则替换
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
System.out.println("复制成功");
} catch (Exception e) {
System.err.println("复制失败: " + e.getMessage());
}
}
}
运行上述代码,若 target.txt 已存在且包含内容,执行后其内容将被 source.txt 覆盖。若未指定 REPLACE_EXISTING,控制台将输出“复制失败”及异常信息。预期结果是目标文件内容与源文件一致,且无异常抛出。
立即学习“Java免费学习笔记(深入)”;
Files.copy() 在跨文件系统时有什么限制?
在大多数操作系统和 JVM 实现中,Files.copy() 不支持跨文件系统(如从本地磁盘复制到网络挂载点)的原子移动或复制,除非底层文件系统支持硬链接或符号链接。此时,它通常会回退到逐字节读取写入模式,这比原子操作慢得多。此外,如果目标路径所在的父目录不存在,Files.copy() 不会自动创建父目录,而是直接抛出 NoSuchFileException。

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.io.IOException;
public class CrossFsCopier {
public static void main(String[] args) {
Path source = Paths.get("/local/source.txt");
Path targetDir = Paths.get("/network/share/target_dir");
Path target = targetDir.resolve("target.txt");
try {
// 确保父目录存在
if (!Files.exists(targetDir)) {
Files.createDirectories(targetDir);
}
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
System.out.println("跨文件系统复制完成");
} catch (IOException e) {
System.err.println("跨文件系统复制失败: " + e.getClass().getSimpleName());
}
}
}
该程序先检查目标父目录是否存在,若不存在则创建。随后执行复制。若跨文件系统操作因权限或类型不支持而失败,将捕获具体的 IOException 子类。预期结果是:若环境支持,文件被复制;若不支持,抛出异常。注意,Files.move() 在跨文件系统时必然失败,但 Files.copy() 通常能工作,只是性能不同。
Files.copy() 返回什么值?
Files.copy() 方法返回一个 Path 对象,该对象代表目标文件的路径。这个返回值与传入的目标路径参数在逻辑上是等价的,但在某些情况下(如符号链接解析),它可能反映实际写入的文件路径。开发者通常忽略此返回值,仅关注是否抛出异常。若需链式调用或进一步处理目标路径,可直接使用该返回值。


















