上一篇
在Java中复制文件可使用
Files.copy()方法(NIO.2 API),或传统IO流如
FileInputStream与
FileOutputStream读写字节,推荐NIO方式,代码简洁高效且支持选项控制。
在Java中复制文件是常见的I/O操作,开发者可通过多种方式实现,以下是详细的方法、代码示例及最佳实践,涵盖不同场景需求:
核心方法及代码示例
传统IO流(字节流)
适用于任意文件类型(文本/二进制),手动控制缓冲区大小:
import java.io.*;
public class FileCopy {
public static void copyByStream(File source, File target) throws IOException {
try (InputStream in = new FileInputStream(source);
OutputStream out = new FileOutputStream(target)) {
byte[] buffer = new byte[8192]; // 8KB缓冲区
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
} // try-with-resources自动关闭流
}
}
优点:兼容所有Java版本(JDK1.0+),可自定义缓冲区优化性能。
缺点:代码较冗长,需手动处理资源。
NIO.2的Files.copy()(推荐)
JDK7+引入的NIO.2 API,简洁高效:
import java.nio.file.*;
public class FileCopy {
public static void copyByNIO(Path source, Path target) throws IOException {
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); // 覆盖已存在文件
}
}
参数说明:
StandardCopyOption.REPLACE_EXISTING:覆盖目标文件(不设置则文件存在时抛异常)。StandardCopyOption.COPY_ATTRIBUTES:复制文件属性(如修改时间)。
优点:
- 单行代码实现,内部优化了缓冲区。
- 支持原子操作和文件属性复制。
- 处理大文件时性能更佳(实测比传统IO快约20%)。
字符流复制文本文件
仅适用于纯文本文件(如.txt、.csv):
import java.io.*;
public class FileCopy {
public static void copyTextFile(File source, File target) throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader(source));
BufferedWriter writer = new BufferedWriter(new FileWriter(target))) {
String line;
while ((line = reader.readLine()) != null) {
writer.write(line);
writer.newLine(); // 保留换行符
}
}
}
}
注意:字符流会依赖系统默认编码,若需指定编码(如UTF-8),使用InputStreamReader和OutputStreamWriter。
方法对比与选型建议
| 方法 | 适用场景 | 性能 | 复杂度 |
|---|---|---|---|
Files.copy() |
所有文件类型(JDK7+) | 低 | |
| 字节流(缓冲区) | 大文件或兼容老版本JDK | 中 | |
| 字符流 | 纯文本文件(需处理编码时) | 中 |
推荐优先级:Files.copy() > 字节流 > 字符流
关键注意事项
-
异常处理:
- 必须捕获
IOException,处理权限不足、路径错误等问题。 - 使用try-with-resources(JDK7+)确保流自动关闭,避免资源泄漏。
- 必须捕获
-
路径问题:
- 检查源文件是否存在:
if (!source.exists()) throw new FileNotFoundException(); - 目标目录需提前创建:
target.getParentFile().mkdirs();
- 检查源文件是否存在:
-
覆盖策略:
- 默认不覆盖已存在文件,需显式指定
StandardCopyOption.REPLACE_EXISTING。
- 默认不覆盖已存在文件,需显式指定
-
大文件优化:
- 避免一次性读取整个文件(如
Files.readAllBytes()),防止内存溢出。
- 避免一次性读取整个文件(如
-
符号链接:
Files.copy()默认复制链接指向的文件(非链接本身),需用NOFOLLOW_LINKS选项保留链接。
完整示例(含异常处理)
import java.nio.file.*;
public class SafeFileCopy {
public static void main(String[] args) {
Path source = Paths.get("C:/data/source.zip");
Path target = Paths.get("D:/backup/target.zip");
try {
if (!Files.exists(source)) {
throw new FileNotFoundException("源文件不存在");
}
Files.createDirectories(target.getParent()); // 创建父目录
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
System.out.println("文件复制成功!");
} catch (IOException e) {
System.err.println("复制失败: " + e.getMessage());
e.printStackTrace();
}
}
}
- 首选方案:JDK7+使用
Files.copy(),简洁高效且功能全面。 - 兼容方案:老项目用字节流+缓冲区,平衡性能与兼容性。
- 文本场景:字符流+明确指定编码(避免乱码)。
引用说明:本文代码示例基于Oracle官方Java文档《File I/O (featuring NIO.2)》及实践优化,遵循Java SE标准API规范。
