1. 引言

在 Java 中,文件复制是最常见的 IO 操作之一。针对不同类型的文件,Java 提供了不同的流来处理:

  • 文本文件(.txt、.java、.html 等):推荐使用 字符流,能正确处理字符编码。
  • 任意文件(图片、视频、音频等):必须使用 字节流,以保证二进制数据的完整性。

为了提高效率,通常会使用 缓冲流 对基础流进行包装,减少与磁盘的交互次数。

2. 文本文件复制 —— 字符缓冲流

2.1 为什么用字符流?

文本文件由字符组成,涉及编码(如 UTF‑8、GBK)。若使用字节流读取,可能会将一个多字节字符截断,产生乱码。字符流内部已封装了编码和解码过程,操作起来更安全、方便。

2.2 代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.io.*;

public class TextFileCopy {
public static void main(String[] args) {
String source = "source.txt"; // 源文件
String target = "target.txt"; // 目标文件

// try-with-resources 自动关闭流
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(); // 写入系统换行符
}
System.out.println("文本文件复制成功!");

} catch (IOException e) {
e.printStackTrace();
}
}
}

要点: try-with-resources 自动关闭流;readLine() 返回的内容不含换行符,需手动写入。

3. 任意文件复制:字节缓冲流(万能复制)

图片、视频、音频等二进制文件必须使用字节流,因为字符流会按编码解析字节,可能损坏数据。字节缓冲流可以原样复制每一个字节。

3.1 核心类

BufferedInputStream

BufferedOutputStream

3.2 代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.io.*;

public class BinaryFileCopy {
public static void main(String[] args) {
String source = "photo.jpg";
String target = "photo_copy.jpg";

try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(target))) {

byte[] buffer = new byte[1024]; // 自定义缓冲区
int len;
while ((len = bis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
System.out.println("二进制文件复制成功!");

} catch (IOException e) {
e.printStackTrace();
}
}
}

自定义缓冲区 比默认的 8KB 更灵活,可根据文件大小调整(如 8192 或更大)。

4. 字符缓冲流 vs 字节缓冲流

对比维度 字符缓冲流 字节缓冲流
适用文件 纯文本文件(.txt, .java, .html) 任何类型文件
核心类 BufferedReader / BufferedWriter BufferedInputStream / BufferedOutputStream
读写单位 字符(16位) 字节(8位)
特殊方法 readLine()、newLine() 无行概念
编码处理 自动(默认系统编码,可指定) 无编码概念,原样复制

5. 实践建议

复制文本文件 → 优先使用字符缓冲流,能正确保留编码和换行。

复制任意文件(万能) → 必须使用字节缓冲流,保证二进制完整性。

无论哪种流,务必使用缓冲包装 和 try-with-resources 保证性能与资源释放。

如需指定编码(如 UTF-8),用 InputStreamReader / OutputStreamWriter 包装字节流并传递 StandardCharsets.UTF_8。

掌握这两种缓冲流的复制方式,就能轻松应对 Java IO 中的各种文件操作需求。