如何使用Apache CSV读取Excel导出CSV文件及空字符问题排查
嘿,这个问题我太熟了!之前帮好几个朋友排查过类似的坑,大概率是字符编码不匹配搞的鬼,我给你拆解下:
问题根源
外部数据源导出的CSV文件,很大可能是用UTF-16编码保存的(Excel有时候会偷偷导出UTF-16 LE带BOM的格式,尤其是非英文环境下)。而你的代码里直接用InputStreamReader读取时,默认用的是当前系统的编码(一般是UTF-8),UTF-16每个字符占2字节,用UTF-8读就会把每个字符的高字节(空字节)当成独立的空字符,就出现了你看到的“每个字符之间被空字符分隔”的情况。
至于手动复制内容重新生成CSV后正常,是因为你复制粘贴的过程中,Excel已经把内容转成了UTF-8(或者你系统默认的兼容编码),所以读取就没问题了。
解决方案
- 先确认编码:用Notepad++这类文本编辑器打开原CSV文件,看一下编码菜单里的选项(比如「编码」→「UTF-16 小端序」是不是被选中),确认原文件的编码格式。
- 修改代码指定编码:在创建
InputStreamReader的时候,明确指定原文件的编码,比如如果是UTF-16,就改成这样:
InputStream is = null; Reader in = null; try { is = new ByteArrayInputStream(excelCSVFileBytes); // 关键:指定正确的编码,比如UTF-16 in = new InputStreamReader(is, StandardCharsets.UTF_16); // 用Excel兼容的格式解析 CSVParser parser = CSVParser.parse(in, CSVFormat.EXCEL); // 后续处理逻辑,比如遍历行 for (CSVRecord record : parser) { // 处理每一行数据 String value = record.get(0); System.out.println(value); } } catch (IOException e) { e.printStackTrace(); } finally { // 别忘了关闭流 if (in != null) { try { in.close(); } catch (IOException ignored) {} } if (is != null) { try { is.close(); } catch (IOException ignored) {} } }
- 如果是带BOM的编码:有些UTF-16文件开头会有BOM(字节顺序标记),如果指定编码后还是有问题,可以用
BOMInputStream(来自Apache Commons IO库)来处理BOM:
// 先引入Apache Commons IO依赖,然后修改流的创建 is = new ByteArrayInputStream(excelCSVFileBytes); BOMInputStream bomInputStream = new BOMInputStream(is); // 获取实际编码,或者直接指定 Charset charset = bomInputStream.getBOM() == BOMInputStream.BOM.UTF_16LE ? StandardCharsets.UTF_16LE : StandardCharsets.UTF_8; in = new InputStreamReader(bomInputStream, charset);
这样应该就能解决你的问题了,试试吧!
内容的提问来源于stack exchange,提问作者Pat's
相关产品推荐
相关产品推荐

