关键在于显式传入匹配文件实际编码的Charset对象,否则默认用系统编码(如Windows上为GBK)易致乱码或MalformedInputException;应使用StandardCharsets常量(如UTF_8),避免字符串拼错,并通过file -i或VS Code验证真实编码。

用 Files.readAllLines() 正确读取特定编码的日志文件,关键在于**显式传入匹配文件实际编码的 Charset 对象**,否则默认使用系统平台编码(如 Windows 上是 GBK),极易导致中文乱码或 MalformedInputException。
确认日志文件的真实编码
不能仅凭文件扩展名或编辑器显示判断。推荐方法:
- 用支持编码检测的工具查看,如 VS Code 右下角显示的编码(注意:它可能只是“猜测”,需验证)
- 用命令行工具验证:
file -i your-log.log(Linux/macOS)或iconv -f utf-8 -t utf-8//strict your-log.log > /dev/null && echo "UTF-8" - 常见日志编码:UTF-8(含 BOM 或无 BOM)、GBK、ISO-8859-1(部分旧系统)、UTF-16LE(少见但存在)
正确调用 readAllLines 并指定 Charset
直接传入 StandardCharsets 中的常量,不要用字符串名构造(如 Charset.forName("UTF-8") 易拼错且不安全):
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
// ✅ 推荐:使用 StandardCharsets 常量
List<String> lines = Files.readAllLines(Paths.get("app.log"), StandardCharsets.UTF_8);
// ✅ 如果是 GBK 编码(如 Windows 默认控制台日志)
lines = Files.readAllLines(Paths.get("error.log"), StandardCharsets.ISO_8859_1); // 注意:GBK 不在 StandardCharsets 中,需用 forName
lines = Files.readAllLines(Paths.get("app.log"), java.nio.charset.Charset.forName("GBK"));
// ❌ 避免:不指定 charset → 使用系统默认,极不可靠
// List<String> lines = Files.readAllLines(Paths.get("app.log"));
处理编码不匹配导致的异常
如果不确定编码,又想避免崩溃,可先尝试常用编码并捕获异常:
public static List<String> readLogSafely(String path) throws IOException {
for (Charset cs : Arrays.asList(
StandardCharsets.UTF_8,
StandardCharsets.ISO_8859_1,
java.nio.charset.Charset.forName("GBK"))) {
try {
return Files.readAllLines(Paths.get(path), cs);
} catch (IOException e) {
if (e instanceof java.nio.charset.MalformedInputException ||
e instanceof java.nio.charset.UnmappableCharacterException) {
continue; // 尝试下一个编码
}
throw e;
}
}
throw new IOException("Unable to decode file with any known charset");
}
补充说明:BOM 的影响
UTF-8 文件带 BOM(EF BB BF)时,StandardCharsets.UTF_8 能自动识别并跳过,无需额外处理;但某些旧工具生成的 UTF-8+BOM 在部分 JDK 版本中可能被误读为乱码首行——此时可先用 Files.readAllBytes() 手动剥离 BOM 再解码,不过多数现代 JDK(8u271+、11+)已修复该问题。

















