
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-io2.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();
⚠️ 注意事项:
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); // 重置流(需更严谨实现)
}
}? 验证与调试技巧:
System.out.println("First line: " + reader.readLine()); // 查看是否含 \uFEFF总结:OpenCSV 本身不内置 BOM 处理机制,必须在 Reader 层预处理。使用 BOMInputStream 是最简洁、可靠且符合 Spring Boot 工程规范的解决方案。