Spring Boot导入CSV到MySQL时TreeMap.getEntryUsingComparator()键值匹配的BOM问题排查咨询
解决CSV导入时第一个表头匹配失败的编码问题
你遇到的这个问题本质是CSV文件的编码格式带BOM(字节顺序标记)且为UTF-16LE编码,直接导致第一个表头的字节结构被干扰了:
- 开头的
[-1,-2]是UTF-16LE的BOM标记(十六进制FF FE),用来标识字节顺序 - 原本的"Id"变成
[73,0,100,0]是因为UTF-16LE用双字节存储每个字符,ASCII字符的高位会补0
下面给你几个可行的解决办法:
方案1:直接转换CSV文件编码(最简单)
用常用的文本编辑器打开你的CSV文件:
- 比如Notepad++:顶部菜单选「编码」→「转为UTF-8无BOM编码」,然后保存
- 比如VS Code:右下角点击编码标识(比如显示“UTF-16 LE”),选择「通过编码保存」→「UTF-8」
重新导入文件,表头匹配应该就正常了。
方案2:在代码中处理BOM和编码
如果需要兼容这种带BOM的UTF-16LE文件,可以修改CSVHelper里的读取逻辑,手动处理BOM并指定编码:
// 示例:用UTF-16LE编码读取并跳过BOM InputStream inputStream = ...; // 你的文件输入流 InputStreamReader reader = new InputStreamReader(inputStream, "UTF-16LE"); // 检查并跳过UTF-16LE的BOM(FF FE) int firstByte = reader.read(); int secondByte = reader.read(); if (!(firstByte == 0xFF && secondByte == 0xFE)) { // 如果没有BOM,把指针移回开头 inputStream.reset(); } // 初始化CSVReader开始读取 CSVReader csvReader = new CSVReader(reader);
方案3:清洗读取到的表头字符串
如果不想改文件编码,也可以在读取表头后,先清洗掉BOM和多余的字节:
// 假设你从CSV里读取到的原始表头是rawHeader String rawHeader = ...; // 跳过前2个BOM字节并转换为正常字符串 byte[] rawBytes = rawHeader.getBytes("UTF-16LE"); byte[] cleanBytes = Arrays.copyOfRange(rawBytes, 2, rawBytes.length); String cleanHeader = new String(cleanBytes, "UTF-16LE"); // 用清洗后的cleanHeader去匹配headerMap if (headerMap.containsKey(cleanHeader)) { // 正常处理逻辑 }
另外给你个小建议:以后导出或创建CSV时,尽量选「UTF-8无BOM」编码,这种格式兼容性最好,能避免大部分编码相关的坑。
内容的提问来源于stack exchange,提问作者Chyuga9
相关产品推荐
相关产品推荐

