Java的Reader不识别BOM,需主动跳过:可用Apache Commons IO的BOMInputStream自动剥离,或手动检查并跳过UTF-8 BOM(EF BB BF),同时必须显式指定UTF-8编码,避免依赖系统默认字符集。

Java 的 Reader 本身不识别 BOM,直接用 InputStreamReader 指定 UTF-8 编码读取带 BOM 的文件时,开头三个字节 EF BB BF 会被当作普通字符解码成 U+FEFF(零宽无间断空格),显示为乱码“”或导致解析失败。解决的关键不是绕开 Reader,而是让 Reader 读取前跳过 BOM。
用 BOMInputStream 自动识别并剥离 BOM
Apache Commons IO 提供了开箱即用的方案:它包装原始输入流,自动检测并跳过 UTF-8、UTF-16BE、UTF-16LE 等常见 BOM,再把干净的流交给 InputStreamReader。
- 添加依赖(Maven):
<dependency><br> <groupId>commons-io</groupId><br> <artifactId>commons-io</artifactId><br> <version>2.11.0</version><br></dependency>
- 代码示例:
try (BOMInputStream bomIn = new BOMInputStream(new FileInputStream("file.txt"));<br> Reader reader = new InputStreamReader(bomIn, bomIn.hasBOM() ? bomIn.getBOMCharsetName() : "UTF-8");<br> BufferedReader br = new BufferedReader(reader)) {<br> String line;<br> while ((line = br.readLine()) != null) {<br> System.out.println(line); // 首行不再含乱码<br> }<br>}
手动检查并跳过 UTF-8 BOM(无需额外依赖)
如果项目不能引入第三方库,可对原始字节流做一次预读判断——只针对 UTF-8 BOM(EF BB BF),简单可靠。
- 用
Files.readAllBytes()一次性读取全部内容,再检查前 3 字节:byte[] data = Files.readAllBytes(Paths.get("file.txt"));<br>if (data.length >= 3 && data[0] == (byte)0xEF && data[1] == (byte)0xBB && data[2] == (byte)0xBF) {<br> data = Arrays.copyOfRange(data, 3, data.length); // 剥离 BOM<br>}<br>String content = new String(data, StandardCharsets.UTF_8); - 适用于中小文件;大文件建议用
InputStream+ByteArrayInputStream组合,先读 3 字节判断,再构建不含 BOM 的新流。
统一源头:保存文件时避免写入 BOM
治本之策是不让 BOM 出现。Windows 记事本默认加 BOM,但 VS Code、Notepad++、IntelliJ IDEA 等现代编辑器都支持“UTF-8 without BOM”保存选项。
立即学习“Java免费学习笔记(深入)”;
- 团队协作中,在 IDE 设置里统一编码:IntelliJ → Settings → Editor → File Encodings → 将 “Default encoding for properties files” 和 “Project Encoding” 都设为 UTF-8,并勾选 “Transparent native-to-ascii conversion”;
- CI/CD 或脚本中可用工具批量清理:Linux 下用
sed -i '1s/^\xEF\xBB\xBF//' file.txt,或 Python 脚本重写无 BOM 版本。
注意 Reader 构造时必须显式指定编码
即使处理了 BOM,仍需确保 InputStreamReader 明确使用 StandardCharsets.UTF_8,绝不能依赖系统默认 Charset。
- ❌ 错误写法:
new InputStreamReader(new FileInputStream(f))—— 在 Windows 上会用 GBK 解码,必然乱码; - ✅ 正确写法:
new InputStreamReader(new FileInputStream(f), StandardCharsets.UTF_8); - 同理,
Files.lines(path)默认用系统编码,应改用Files.lines(path, StandardCharsets.UTF_8)。


















