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规范。
原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/44208.html