按指定格式写入CSV异常:最后一行缺失竖线问题排查
我来帮你排查并解决这个竖线分隔CSV的格式异常问题,咱们一步步梳理:
需求目标
我们需要生成符合以下格式的竖线分隔CSV:
Redemption Reference Code|Status|Delivery company|Shipper Tracking Number|Comments 2006995040|Shipped|USPS|ABCD12345|Order SHIPPED 2006995042|Cancelled|||INVALID Address 2006995048|Ordered|USPS|ABCD12345|Order SHIPPED
当前实现代码
1. 订单数据收集逻辑
private void accumulateOrdersFromPlacement(){ int count = 0; for (int i = 0; i < orderIds.size(); i++) { if (count == 0) { outPutLineData.add(orderIds.get(i)); outPutLineData.add("Cancelled"); outPutLineData.add(""); outPutLineData.add(" "); outPutLineData.add(" "); cancelledStatusLineItems.add(orderIds.get(i)); count++; } else if (count == 1) { outPutLineData.add(orderIds.get(i)); outPutLineData.add("Shipped"); if (outPutLineData.contains("Shipped")) { outPutLineData.add("USPS"); outPutLineData.add("order SHIPPED"); outPutLineData.add(""); } shippedStatusLineItems.add(orderIds.get(i)); count++; } else if (count == 2) { outPutLineData.add(orderIds.get(i)); outPutLineData.add("No Longer Available"); outPutLineData.add(""); outPutLineData.add(" "); outPutLineData.add(" "); count++; nlaStatusLineItems.add(orderIds.get(i)); } else if (count == 3) { outPutLineData.add(orderIds.get(i)); outPutLineData.add("Ordered"); outPutLineData.add(""); outPutLineData.add(" "); outPutLineData.add(" "); orderedStatusLineItems.add(orderIds.get(i)); count = 0; } } }
2. 文件生成逻辑
private File createFile(final File directory) { FileWriter fw = null; File tempFile = null; try { directory.mkdir(); tempFile = new File(".//FidelityFulfillment//" + generateFileName(countyThreeLetterCode, "FidelityFulfillment", ".csv", date)); logReport(GenericConstants.NEW_LINE + "Fulfillment file creating:", tempFile.getName()); fw = new FileWriter(tempFile, true); try (BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile, true))) { writer.write(generateHeaderLine()); writer.newLine(); for (int y = 1; y < outPutLineData.size(); y++) { if (y % 5 < 4) { writer.write(outPutLineData.get(y-1) + fieldSeperator); logReport(outPutLineData.get(y - 1) + fieldSeperator); } else { writer.write(outPutLineData.get(y-1)); logReport(outPutLineData.get(y)); } if (y % 5 == 0) { writer.newLine(); logReport("newline"); } } writer.close(); } catch (final IOException e) { e.printStackTrace(); final String err = "Unable to write file due to : " + e; logReport(GenericConstants.NEW_LINE + "Unable to create temp local File"); } finally { fw.close(); } }catch (Exception e){ e.printStackTrace(); } return tempFile; }
问题现象
实际输出的CSV存在格式异常,最后一行缺失竖线,字段不完整:
Redemption Reference Code|Status|Delivery company|ShipperTrackingNumber|Comments 2006964032|Cancelled|| | newline 2006964034|Shipped|USPS|| newline 2006964036|No Longer Available||
问题排查与修复
1. 核心问题分析
文件生成的循环逻辑存在两个致命问题:
- 遗漏最后一个元素:循环条件
y < outPutLineData.size()导致最后一个元素(索引size-1)永远不会被写入,直接造成最后一行字段缺失 - 字段分隔逻辑混乱:用
y%5 <4判断是否加分隔符的逻辑,在处理非5的整数倍元素时,会导致最后一行的分隔符不完整
另外还有一个次要问题:代码中创建了重复的FileWriter,既容易导致资源泄露,也可能造成文件追加异常。
2. 修复方案
方案一:重构文件生成的循环逻辑
把循环改成按字段遍历,确保每个元素都被处理,并且每行的5个字段严格用竖线分隔:
// 替换原有的循环代码 for (int i = 0; i < outPutLineData.size(); i++) { String field = outPutLineData.get(i); // 不是当前行最后一个字段,就添加分隔符 if ((i + 1) % 5 != 0) { writer.write(field + fieldSeperator); logReport(field + fieldSeperator); } else { // 当前行最后一个字段,直接写入后换行 writer.write(field); logReport(field); writer.newLine(); logReport("newline"); } }
方案二:清理冗余代码与优化
- 去掉重复的
FileWriter fw,用try-with-resources自动管理资源 - 用
directory.mkdirs()代替mkdir(),确保父目录不存在时也能创建成功 - 移除
accumulateOrdersFromPlacement中多余的if (outPutLineData.contains("Shipped"))判断(刚添加的元素必然存在,逻辑冗余)
修复后的完整createFile方法:
private File createFile(final File directory) { File tempFile = null; try { // 确保所有父目录都能被创建 directory.mkdirs(); tempFile = new File(".//FidelityFulfillment//" + generateFileName(countyThreeLetterCode, "FidelityFulfillment", ".csv", date)); logReport(GenericConstants.NEW_LINE + "Fulfillment file creating:", tempFile.getName()); // try-with-resources自动关闭writer,无需手动调用close try (BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile))) { writer.write(generateHeaderLine()); writer.newLine(); // 遍历所有字段,按每行5个字段处理 for (int i = 0; i < outPutLineData.size(); i++) { String field = outPutLineData.get(i); if ((i + 1) % 5 != 0) { writer.write(field + fieldSeperator); logReport(field + fieldSeperator); } else { writer.write(field); logReport(field); writer.newLine(); logReport("newline"); } } } catch (final IOException e) { e.printStackTrace(); String err = "Unable to write file due to : " + e; logReport(GenericConstants.NEW_LINE + err); } } catch (Exception e) { e.printStackTrace(); logReport(GenericConstants.NEW_LINE + "Failed to create file: " + e.getMessage()); } return tempFile; }
3. 验证效果
修复后,生成的CSV每行都会严格包含5个字段,用4个竖线分隔,不会出现最后一行缺失竖线或字段的情况,完全符合需求格式。
内容的提问来源于stack exchange,提问作者Soorya Thomas
相关产品推荐
相关产品推荐

