如何使用Java移除CSV文件中的重复列解决数据库插入异常
核心实现逻辑
整个方案无需复杂依赖设计,核心流程分为两步,可完全匹配目标列结构要求:
- 第一步:读取CSV首行表头,从左到右遍历每个列名,记录每个列名第一次出现时对应的索引位置;已经记录过的重复列名,对应的索引直接标记为丢弃,不纳入保留范围。
- 第二步:逐行读取后续所有数据行,只按照第一步得到的保留索引列表提取对应位置的字段值,跳过被标记为重复的列位置,最终将清理后的表头和数据行重新写入新的CSV文件。
说明:这套逻辑处理原始列结构时,会按从左到右的顺序保留Name(索引0)、Email(1)、PhoneNo(2)、Address(3)、BankAcc(4)、AccType(6)、CreditScore(8)、State(10),最终生成的列结构和预期完全一致。
落地实现步骤
- 解析原始CSV表头构建保留索引集合
遍历所有表头列名,用哈希集合存储已出现过的列名:遇到新的列名就将当前索引加入保留列表,同时把列名存入哈希集合;遇到已经在集合里的列名,直接跳过当前索引。 - 逐行处理数据行
按照保留索引列表,从每一行解析出的字段数组中提取对应值,越界的位置自动补空值,避免异常列数导致程序崩溃。 - 写入规范化CSV文件
先写入去重后的表头,再逐行写入处理好的数据行,保证文件格式合规。
代码实现示例
如果CSV是简单结构(字段内无内嵌逗号、引号、换行符),可以直接用JDK基础IO实现,无需引入第三方依赖:
import java.io.*; import java.util.*; public class CsvColumnDeduplicator { public static void main(String[] args) throws IOException { // 配置原始CSV路径和输出文件路径 String rawFilePath = "input_raw.csv"; String outputFilePath = "output_cleaned.csv"; BufferedReader br = new BufferedReader(new FileReader(rawFilePath)); // 解析表头生成保留索引 String headerLine = br.readLine(); String[] originColumns = headerLine.split(","); Set<String> existedColumnSet = new HashSet<>(); List<Integer> keepIndex = new ArrayList<>(); List<String> cleanedHeaders = new ArrayList<>(); for (int i = 0; i < originColumns.length; i++) { String colName = originColumns[i].trim(); if (!existedColumnSet.contains(colName)) { existedColumnSet.add(colName); keepIndex.add(i); cleanedHeaders.add(colName); } } // 逐行处理数据并写入新文件 BufferedWriter bw = new BufferedWriter(new FileWriter(outputFilePath)); bw.write(String.join(",", cleanedHeaders)); bw.newLine(); String line; while ((line = br.readLine()) != null) { String[] rowValues = line.split(","); List<String> cleanedRow = new ArrayList<>(); for (int idx : keepIndex) { cleanedRow.add(idx < rowValues.length ? rowValues[idx] : ""); } bw.write(String.join(",", cleanedRow)); bw.newLine(); } br.close(); bw.close(); } }
注意事项:如果CSV字段本身包含内嵌逗号、双引号、换行符,简单用split(",")会导致列错位,这种场景下建议替换为成熟的CSV解析组件(如Apache Commons CSV、OpenCSV)的行解析能力,核心的列去重逻辑不需要改动,仅替换字段解析的实现即可。比如基于Commons CSV的核心解析片段:
// 用成熟组件解析整行字段,避免转义字符导致的列错位 CSVParser parser = CSVParser.builder() .setFile(new File(rawFilePath)) .setFormat(CSVFormat.DEFAULT) .get(); String[] rawHeader = parser.getHeaderNames().toArray(new String[0]); // 后续构建保留索引、提取行数据的逻辑和上面完全一致
可调整的规则说明
- 默认策略为保留第一次出现的列,严格匹配预期列顺序,不会打乱原有业务字段的排列位置。
- 如果需要调整去重判定规则(比如忽略列名大小写、重复列保留最后一次出现的字段值),仅需要修改表头遍历时的判定逻辑,整体流程无需改动。
- 异常行兼容:遇到列数比表头少的异常数据行,会在缺失的列位置自动填空字符串,不会因为单行格式问题导致整个任务中断。
内容的提问来源于stack exchange,提问作者HegdeS
相关产品推荐
相关产品推荐

