如何用Jackson实现CSV文件中指定ID行的删除与新增
要实现这个逻辑,核心是先读取CSV所有内容,过滤掉冲突的id行,再合并新数据后重新写入——因为CSV是纯文本文件,没法直接修改某一行,只能全量读写。
具体实现步骤
- 读取现有CSV的所有数据(包括表头)
- 将传入的新数据按
id构建Map,快速判断哪些id需要替换 - 过滤原有数据:保留那些id不在新数据Map中的行
- 合并过滤后的旧数据 + 新数据,重新写入CSV(覆盖原文件,不是追加)
修改后的代码实现
确保你的EmpData类有getId()方法(用来匹配唯一标识),然后修改addOrUpdate方法:
public static void addOrUpdate(File file, List<EmpData> newData) { CsvMapper mapper = new CsvMapper(); mapper.configure(JsonGenerator.Feature.IGNORE_UNKNOWN, true); CsvSchema schema = mapper.schemaFor(EmpData.class) .withColumnSeparator(',') .withHeader(); // 明确使用表头,避免数据错位 try { // 1. 读取现有CSV数据(文件不存在/为空时跳过) List<EmpData> existingData = new ArrayList<>(); if (file.exists() && file.length() > 0) { ObjectReader reader = mapper.readerFor(EmpData.class).with(schema); existingData = reader.<EmpData>readValues(file).readAll(); } // 2. 将新数据按id分组,快速判断重复 Map<Integer, EmpData> newDataMap = newData.stream() .collect(Collectors.toMap(EmpData::getId, data -> data)); // 3. 过滤现有数据:移除和新数据id重复的行 List<EmpData> filteredData = existingData.stream() .filter(data -> !newDataMap.containsKey(data.getId())) .collect(Collectors.toList()); // 4. 合并旧数据(过滤后)和新数据 filteredData.addAll(newData); // 5. 重新写入CSV(覆盖原文件,而非追加) ObjectWriter writer = mapper.writerFor(EmpData.class).with(schema); try (OutputStream os = new FileOutputStream(file)) { writer.writeValues(os).writeAll(filteredData); } } catch (IOException e) { throw new RuntimeException("处理CSV文件失败", e); } }
关键细节说明
- 表头处理:
withHeader()确保读写时都识别表头,避免字段顺序错乱 - 文件兼容性:处理了文件不存在、空文件的情况,直接写入新数据即可
- 覆盖写入:去掉了
FileOutputStream的true参数,改为覆盖原文件,彻底避免重复数据 - 性能优化:用Map存储新数据的id,判断重复的时间复杂度从O(n*m)降到O(n),数据量大时更高效
- 资源安全:用try-with-resources自动关闭OutputStream,避免资源泄漏
额外注意事项
- 如果你的
id不是Integer类型,把Map的key类型改成对应类型(比如String) - 如果CSV有特殊格式需求(比如引号包裹字段、换行符),可以调整CsvSchema的配置(如
withQuoteChar('"')) - 大文件场景:如果CSV文件非常大,全量读写可能内存不足,这时可以考虑逐行读取+写入临时文件,最后替换原文件
内容的提问来源于stack exchange,提问作者ppb
相关产品推荐
相关产品推荐

