核心思想
转换文件编码的核心步骤如下:

- 以源编码(GBK)读取文件内容,将其读入内存中(通常是
String或byte[])。 - 以目标编码(UTF-8)将内容写入新文件。
使用 Java 原生 I/O (不推荐,但有助于理解原理)
这种方法使用 InputStreamReader 和 OutputStreamWriter,它们是处理字符流和字节流之间编码转换的核心类。
缺点:
- 代码相对冗长。
- 需要手动处理资源关闭(使用
try-finally),容易出错。 - 对于大文件,一次性读取到内存中可能导致
OutOfMemoryError。
import java.io.*;
import java.nio.charset.StandardCharsets;
public class GbkToUtf8Native {
public static void convert(String sourceFilePath, String targetFilePath) {
// 1. 使用 GBK 编码读取源文件
// 2. 使用 UTF-8 编码写入目标文件
try (
// 使用 try-with-resources 自动关闭资源
InputStreamReader isr = new InputStreamReader(new FileInputStream(sourceFilePath), "GBK");
BufferedReader br = new BufferedReader(isr);
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(targetFilePath), StandardCharsets.UTF_8);
BufferedWriter bw = new BufferedWriter(osw)
) {
String line;
// 逐行读取,避免内存溢出
while ((line = br.readLine()) != null) {
bw.write(line);
// 写入换行符,因为 readLine() 会消耗掉换行符
bw.newLine();
}
System.out.println("文件转换成功: " + sourceFilePath + " -> " + targetFilePath);
} catch (UnsupportedEncodingException e) {
System.err.println("不支持的编码格式: " + e.getMessage());
} catch (FileNotFoundException e) {
System.err.println("文件未找到: " + e.getMessage());
} catch (IOException e) {
System.err.println("发生IO异常: " + e.getMessage());
}
}
public static void main(String[] args) {
String sourceFile = "source_gbk.txt"; // 假设这是一个GBK编码的文件
String targetFile = "target_utf8.txt"; // 这是将要生成的UTF-8编码的文件
// 为了演示,我们先创建一个GBK编码的测试文件
createGbkFile(sourceFile);
convert(sourceFile, targetFile);
}
// 辅助方法:创建一个GBK编码的测试文件
private static void createGbkFile(String filePath) {
try (OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filePath), "GBK")) {
osw.write("你好,世界!\n");
osw.write("This is a test file.\n");
osw.write("GBK to UTF-8 conversion.\n");
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用 Java NIO (推荐,更现代的方式)
Java NIO (New I/O) 提供了更高效、更灵活的文件操作方式。Files 类的 readAllLines 和 write 方法可以极大地简化代码。
优点:

- 代码简洁。
Files.readAllLines会自动处理字符编码。- 同样使用
try-with-resources管理资源。
注意:Files.readAllLines 会将整个文件内容读入内存,因此不适合处理非常大的文件,对于大文件,应使用 Files.lines() 方法(见方法三)。
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class GbkToUtf8Nio {
public static void convert(String sourceFilePath, String targetFilePath) {
Path sourcePath = Paths.get(sourceFilePath);
Path targetPath = Paths.get(targetFilePath);
try {
// 1. 以 GBK 编码读取所有行到 List<String>
List<String> lines = Files.readAllLines(sourcePath, Charset.forName("GBK"));
// 2. 以 UTF-8 编码将所有行写入新文件
// StandardCharsets.UTF_8 是一个预定义的常量,比 "UTF-8" 字符串更高效
Files.write(targetPath, lines, StandardCharsets.UTF_8);
System.out.println("文件转换成功: " + sourceFilePath + " -> " + targetFilePath);
} catch (IOException e) {
System.err.println("文件转换失败: " + e.getMessage());
e.printStackTrace();
}
}
public static void main(String[] args) {
String sourceFile = "source_gbk.txt";
String targetFile = "target_utf8_nio.txt";
createGbkFile(sourceFile); // 复用上面方法一的辅助方法
convert(sourceFile, targetFile);
}
// 辅助方法同上...
private static void createGbkFile(String filePath) { /* ... */ }
}
使用 Java NIO 流式处理 (最佳实践,适用于大文件)
如果文件非常大(例如几百MB或GB),使用 readAllLines 会导致内存溢出,应该使用 Files.lines() 方法,它会返回一个 Stream<String>,我们可以逐行处理并写入新文件,这是最节省内存的方式。
优点:
- 内存效率极高,适合处理任意大小的文件。
- 代码依然很简洁。
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
public class GbkToUtf8NioStream {
public static void convert(String sourceFilePath, String targetFilePath) {
Path sourcePath = Paths.get(sourceFilePath);
Path targetPath = Paths.get(targetFilePath);
// 使用 try-with-resources 确保 Stream 和 BufferedWriter 都被正确关闭
try (
// 1. 以 GBK 编码创建一个行流
Stream<String> lines = Files.lines(sourcePath, Charset.forName("GBK"));
// 2. 以 UTF-8 编码创建一个缓冲写入器
BufferedWriter writer = Files.newBufferedWriter(targetPath, StandardCharsets.UTF_8)
) {
// 3. 逐行处理并写入
// forEach 会保持流的顺序,非常适合此场景
lines.forEach(line -> {
try {
writer.write(line);
writer.newLine(); // 写入换行符
} catch (IOException e) {
// 将受检异常转为非受检异常,以便 Stream 的 forEach 能处理
throw new RuntimeException("写入文件时发生错误", e);
}
});
System.out.println("大文件转换成功: " + sourceFilePath + " -> " + targetFilePath);
} catch (IOException e) {
System.err.println("文件转换失败: " + e.getMessage());
e.printStackTrace();
}
}
public static void main(String[] args) {
String sourceFile = "source_gbk.txt";
String targetFile = "target_utf8_nio_stream.txt";
createGbkFile(sourceFile); // 复用上面方法一的辅助方法
convert(sourceFile, targetFile);
}
// 辅助方法同上...
private static void createGbkFile(String filePath) { /* ... */ }
}
使用 Apache Commons IO (最健壮、最推荐的方式)
如果你的项目已经引入了 Apache Commons IO 库,或者你想要一个经过充分测试、功能更强大的工具,IOUtils 是最佳选择。

添加 Maven 依赖:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version> <!-- 请使用最新版本 -->
</dependency>
优点:
- 代码极其简洁。
- 底层已经处理了各种边界情况和资源管理,非常健壮。
IOUtils.copy()方法可以自动处理缓冲,效率很高。
import org.apache.commons.io.IOUtils;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
public class GbkToUtf8CommonsIo {
public static void convert(String sourceFilePath, String targetFilePath) {
try (
// 以 GBK 编码创建输入流
FileInputStream fis = new FileInputStream(sourceFilePath);
InputStreamReader isr = new InputStreamReader(fis, "GBK");
// 以 UTF-8 编码创建输出流
FileOutputStream fos = new FileOutputStream(targetFilePath);
OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
) {
// 一行代码搞定复制和编码转换
IOUtils.copy(isr, osw);
System.out.println("文件转换成功 (使用 Commons IO): " + sourceFilePath + " -> " + targetFilePath);
} catch (IOException e) {
System.err.println("文件转换失败: " + e.getMessage());
e.printStackTrace();
}
}
public static void main(String[] args) {
String sourceFile = "source_gbk.txt";
String targetFile = "target_utf8_commons_io.txt";
createGbkFile(sourceFile); // 复用上面方法一的辅助方法
convert(sourceFile, targetFile);
}
// 辅助方法同上...
private static void createGbkFile(String filePath) { /* ... */ }
}
总结与建议
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 原生 I/O | 原理清晰,无需额外库 | 代码冗长,易出错 | 学习原理,简单脚本 |
Java NIO (readAllLines) |
代码简洁,现代API | 内存占用高,不适合大文件 | 中小文件,追求代码简洁 |
Java NIO (lines) |
内存占用极低,代码简洁 | 略比 readAllLines 复杂一点 |
大文件处理的首选,通用性最强 |
| Apache Commons IO | 代码最简洁,最健壮,功能强大 | 需要引入第三方库 | 生产环境推荐,特别是已有项目依赖 |
推荐选择:
- 新项目/生产环境:优先选择 方法三 (Java NIO 流式处理) 或 方法四 (Apache Commons IO),方法三更“原生”,方法四更“省心”。
- 快速脚本/学习:可以使用 方法二 (Java NIO
readAllLines),但要确保文件不大。 - 理解底层:可以看看 方法一 (原生 I/O) 的实现。
