Java实现基于多列匹配筛选CSV文件并生成新文件
Java实现CSV文件匹配筛选
输入文件示例
文件1(file1.csv):
ID,NAME 1,FOO 2,BAR 3,XYZ
文件2(file2.csv):
ID,NAME,DOB 3,XYZ,02/03/1999 4,BAR,01/01/1995 1,FOO,01/01/1996
预期输出
ID,NAME,DOB 3,XYZ,02/03/1999 1,FOO,01/01/1996
核心实现思路
- 先读取文件1,将所有
(ID, NAME)组合存入HashSet,利用集合的O(1)查找特性提升匹配效率 - 遍历文件2的每一行,检查当前行的
ID和NAME是否存在于上述集合中 - 将符合条件的行(包含表头)写入结果文件
使用OpenCSV库实现
原生Java处理CSV需要手动处理分隔符、转义字符等场景,容易出错,推荐使用成熟的第三方库OpenCSV简化操作。
引入依赖(Maven)
<dependency> <groupId>com.opencsv</groupId> <artifactId>opencsv</artifactId> <version>5.6</version> </dependency>
完整代码示例(适用于中小文件)
该版本一次性读取文件内容到内存,适合文件体积不大的场景:
import com.opencsv.CSVReader; import com.opencsv.CSVWriter; import com.opencsv.exceptions.CsvException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.HashSet; import java.util.List; import java.util.Set; public class CsvMatcher { public static void main(String[] args) { String file1Path = "path/to/file1.csv"; String file2Path = "path/to/file2.csv"; String outputPath = "path/to/result.csv"; Set<String> matchPairs = new HashSet<>(); // 读取文件1,构建匹配集合 try (CSVReader reader1 = new CSVReader(new FileReader(file1Path))) { List<String[]> allRows = reader1.readAll(); // 跳过表头,从第二行开始处理数据 for (int i = 1; i < allRows.size(); i++) { String[] row = allRows.get(i); if (row.length >= 2) { // 拼接ID和NAME作为匹配键,trim避免空格干扰 String key = row[0].trim() + "," + row[1].trim(); matchPairs.add(key); } } } catch (IOException | CsvException e) { e.printStackTrace(); return; } // 读取文件2并筛选符合条件的行 try (CSVReader reader2 = new CSVReader(new FileReader(file2Path)); CSVWriter writer = new CSVWriter(new FileWriter(outputPath))) { List<String[]> file2Rows = reader2.readAll(); // 先写入表头 writer.writeNext(file2Rows.get(0)); // 遍历数据行,筛选匹配项 for (int i = 1; i < file2Rows.size(); i++) { String[] row = file2Rows.get(i); if (row.length >= 3) { String key = row[0].trim() + "," + row[1].trim(); if (matchPairs.contains(key)) { writer.writeNext(row); } } } System.out.println("筛选完成,结果已写入:" + outputPath); } catch (IOException | CsvException e) { e.printStackTrace(); } } }
大文件优化版本(逐行读取)
如果CSV文件体积较大,一次性读入内存会导致内存溢出,可改用逐行读取的方式:
import com.opencsv.CSVReader; import com.opencsv.CSVWriter; import com.opencsv.exceptions.CsvException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.HashSet; import java.util.Set; public class LargeCsvMatcher { public static void main(String[] args) { String file1Path = "path/to/file1.csv"; String file2Path = "path/to/file2.csv"; String outputPath = "path/to/result.csv"; Set<String> matchPairs = new HashSet<>(); // 逐行读取文件1 try (CSVReader reader1 = new CSVReader(new FileReader(file1Path))) { String[] nextLine; // 跳过表头 reader1.readNext(); while ((nextLine = reader1.readNext()) != null) { if (nextLine.length >= 2) { String key = nextLine[0].trim() + "," + nextLine[1].trim(); matchPairs.add(key); } } } catch (IOException | CsvException e) { e.printStackTrace(); return; } // 逐行读取文件2并筛选 try (CSVReader reader2 = new CSVReader(new FileReader(file2Path)); CSVWriter writer = new CSVWriter(new FileWriter(outputPath))) { // 写入表头 String[] header = reader2.readNext(); if (header != null) { writer.writeNext(header); } String[] nextLine; while ((nextLine = reader2.readNext()) != null) { if (nextLine.length >= 3) { String key = nextLine[0].trim() + "," + nextLine[1].trim(); if (matchPairs.contains(key)) { writer.writeNext(nextLine); } } } System.out.println("筛选完成,结果已写入:" + outputPath); } catch (IOException | CsvException e) { e.printStackTrace(); } } }
注意事项
- 替换代码中的文件路径为实际的本地文件路径
- 使用
trim()是为了避免字段前后的空格导致匹配失败,如果确认CSV文件中没有多余空格,可以去掉该方法 - 如果需要处理带引号的CSV字段,OpenCSV会自动处理,无需额外编码
内容的提问来源于stack exchange,提问作者rahulpareekyx
相关产品推荐
相关产品推荐

