Apache Commons CSVPrinter输出Double值自动转科学计数法如何解决
问题根因
你遇到的问题本质是Double类默认的toString()方法逻辑导致的:当数值绝对值小于1e-3或者大于等于1e7时,会自动返回科学计数法格式的字符串,Commons CSV的printRecords方法默认调用元素的toString()方法做序列化,所以会输出科学计数法。
可用解决方案
方案1:遍历记录手动格式化Double字段(兼容性最好)
不要直接调用printRecords传入整个列表,逐条处理每一条记录,对Double类型字段用DecimalFormat或String.format转成非科学计数法字符串后再打印,示例代码:
// 先定义格式化器,按需调整保留小数位数,这里示例保留最多9位小数,不会补末尾0 DecimalFormat decimalFormat = new DecimalFormat("0.#########"); decimalFormat.setGroupingUsed(false); // 关闭千位分隔符,避免出现逗号分隔的数值 try (BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(fileName)); CSVPrinter csvPrinter = CSVFormat.DEFAULT .withEscape(Character.MIN_VALUE) .withQuoteMode(QuoteMode.NONE) .withHeader(HEADERS) .withIgnoreHeaderCase() .withTrim() .print(bufferedWriter)) { // 遍历原list逐条打印 for (Object record : list) { // 替换为你实际的业务对象字段读取逻辑 YourDataRow row = (YourDataRow) record; csvPrinter.print(row.getNormalField()); // 仅对Double字段做手动格式化 csvPrinter.print(decimalFormat.format(row.getDoubleField())); // 其余字段按实际需求处理 csvPrinter.println(); // 结束当前行 } }
方案2:提前转换字段类型
如果不想改打印逻辑,可以在构造输入list的阶段,就把所有Double类型的字段提前格式化为符合要求的字符串,再把处理后的列表传给printRecords即可,不需要调整CSVPrinter的原有配置。
方案3:使用Commons CSV 1.10+版本的类型转换器(最简配置)
如果你用的是1.10及以上版本的Commons CSV,可以直接注册Double类型的全局转换器,不需要修改遍历逻辑:
DecimalFormat decimalFormat = new DecimalFormat("0.#########"); decimalFormat.setGroupingUsed(false); try (BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(fileName)); CSVPrinter csvPrinter = CSVFormat.DEFAULT .withEscape(Character.MIN_VALUE) .withQuoteMode(QuoteMode.NONE) .withHeader(HEADERS) .withIgnoreHeaderCase() .withTrim() // 注册Double类型转换器,全局生效 .withConverter(Double.class, (value, format) -> decimalFormat.format(value)) .print(bufferedWriter)) { csvPrinter.printRecords(list); }
额外提示:你原代码里用了try-with-resources语法声明bufferedWriter和csvPrinter后,不需要手动调用flush和close方法,资源会在try块结束后自动关闭,手动调用属于冗余逻辑还可能引发异常。
内容的提问来源于stack exchange,提问作者Akif
相关产品推荐
相关产品推荐

