
opencsv 在 spring boot 中解析 csv 时首列值为 null,通常是由 utf-8 bom(字节顺序标记 \ufeff)引起;文件开头隐藏的 bom 被误读为第一列字段名前缀,导致列名匹配失败。
在使用 OpenCSV 的 CsvToBeanBuilder 解析带表头的 CSV 文件时,若首列(如 "Departure")始终返回 null,而其余列正常,极大概率是 CSV 文件以 UTF-8 with BOM 编码保存——Windows 系统下常见编辑器(如记事本、部分版本的 IntelliJ IDEA)默认添加不可见的 BOM 字符 \uFEFF 到文件开头。该字符会“污染”首列字段名,使 OpenCSV 实际匹配的列为 "\uFEFFDeparture",而非预期的 "Departure",从而导致绑定失败。
✅ 正确做法:在构造 Reader 时显式剥离 BOM
推荐使用 Apache Commons IO 提供的 BOMInputStream(需引入依赖):
commons-io commons-io 2.11.0
然后修改读取逻辑如下:
import org.apache.commons.io.input.BOMInputStream; import java.io.FileInputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; // ... InputStream input = new FileInputStream(path); Reader reader = new InputStreamReader(new BOMInputStream(input), StandardCharsets.UTF_8); CsvToBeancsvToBean = new CsvToBeanBuilder<>(reader) .withType(CsvBikeTrips.class) .withIgnoreLeadingWhiteSpace(true) // 建议启用,增强鲁棒性 .withSkipLines(0) // 若含 BOM,无需额外跳过行 .build(); List trips = csvToBean.parse();
⚠️ 注意事项:
- 不要手动用 Files.newBufferedReader(Paths.get(path)),它无法自动处理 BOM;
- 避免使用 new InputStreamReader(new FileInputStream(...), "UTF-8")(未处理 BOM);
- withIgnoreLeadingWhiteSpace(false) 可保留,但建议设为 true 以兼容字段前后空格;
- 若无法引入 commons-io,可手动跳过 BOM(不推荐):
InputStream is = new FileInputStream(path); if (is.available() >= 3) { byte[] bom = new byte[3]; is.read(bom); if (!(bom[0] == (byte)0xEF && bom[1] == (byte)0xBB && bom[2] == (byte)0xBF)) { is = new ByteArrayInputStream(bom); // 重置流(需更严谨实现) } }
? 验证与调试技巧:
- 用十六进制编辑器(如 HxD)或命令行 xxd -g1 file.csv | head 检查文件开头是否含 ef bb bf;
- 在代码中打印实际读取的首行字段名:
System.out.println("First line: " + reader.readLine()); // 查看是否含 \uFEFF
总结:OpenCSV 本身不内置 BOM 处理机制,必须在 Reader 层预处理。使用 BOMInputStream 是最简洁、可靠且符合 Spring Boot 工程规范的解决方案。










