比较Java中的两个csv文件

我们需要比较两个CSV文件。 假设文件一行有几行,第二个文件可以有相同的行数或更多行。 大多数行可以在两个文件上保持相同。寻找在这两个文件之间进行差异的最佳方法,并只读取第二个文件与第一个文件有差异的那些行。 处理文件的应用程序是Java。

有什么最好的方法?

注意:如果我们知道在第二个文件中更新,插入或删除了一行,那将会很棒。

要求:-

  1. 不会有任何重复记录
  2. 文件1和文件2可以具有相同的no记录,其中几行具有file2中的更新值(记录已更新)
  3. 文件2可能删除了几行(这被视为已删除的记录)
  4. 文件2可能会添加一些新行(这被视为已插入记录)
  5. 列的开头可以被视为记录的主键,在两个文件中都不会改变。

这样做的一种方法是使用java的Set接口; 将每一行作为字符串读取,将其添加到集合中,然后使用第一个集合上的第二个集合执行removeAll() ,从而保留不同的行。 当然,这假定文件中没有重复的行。

 // using FileUtils to read in the files. HashSet f1 = new HashSet(FileUtils.readLines("file1.csv")); HashSet f2 = new HashSet(FileUtils.readLines("file2.csv")); f1.removeAll(f2); // f1 now contains only the lines which are not in f2 

更新

好的,所以你有一个PK领域。 我只是假设你知道如何从你的字符串中得到它; 使用openCSV或正则表达式或任何你想要的。 如上所述制作一个实际的HashMap而不是HashSet ,使用PK作为键,使用行作为值。

 HashMap f1 = new HashMap(); HashMap f2 = new HashMap(); // read f1, f2; use PK field as the key List deleted = new ArrayList(); List updated = new ArrayList(); for(Map.Entry entry : f1.keySet()) { if(!f2.containsKey(entry.getKey()) { deleted.add(entry.getValue()); } else { if(!f2.get(entry.getKey().equals(f1.getValue())) { updated.add(f1.getValue()); } } } for(String key : f1.keySet()) { f2.remove(key); } // f2 now contains only "new" rows 

读取整个第一个文件,并将其放入List 。 然后一次读取第二行文件,并将每行与第一个文件的所有行进行比较,看它是否重复。 如果它不重复,那么它就是新信息。 如果您在阅读时遇到问题,请查看http://opencsv.sourceforge.net/ ,它是一个非常好的用于在Java中读取CSV文件的库。

尝试使用java-diff-utils库

我使用groovy快速演示java库:

两个示例文件之间报告了以下差异:

 $ groovy diff [ChangeDelta, position: 0, lines: [1,11,21,31,41,51] to [1,11,99,31,41,51]] [DeleteDelta, position: 2, lines: [3,13,23,33,43,53]] [InsertDelta, position: 5, lines: [6,16,26,36,46,56]] 

files1.csv

 1,11,21,31,41,51 2,12,22,32,42,52 3,13,23,33,43,53 4,14,24,34,44,54 5,15,25,35,45,55 

file2.csv

 1,11,99,31,41,51 2,12,22,32,42,52 4,14,24,34,44,54 5,15,25,35,45,55 6,16,26,36,46,56 

diff.groovy

 // // Dependencies // ============ import difflib.* @Grapes([ @Grab(group='com.googlecode.java-diff-utils', module='diffutils', version='1.2.1'), ]) // // Main program // ============ def original = new File("file1.csv").readLines() def revised = new File("file2.csv").readLines() Patch patch = DiffUtils.diff(original, revised) patch.getDeltas().each { println it } 

更新

根据dbunit FAQ ,通过使用ResultSetTableFactory接口的流式修订,可以针对非常大的数据集改进此解决方案的性能。 这在ANT任务中启用如下:

 ant.dbunit(driver:driver, url:url, userid:user, password:pass) { compare(src:"dbunit.xml", format:"flat") dbconfig { property(name:"datatypeFactory", value:"org.dbunit.ext.h2.H2DataTypeFactory") property(name:"resultSetTableFactory", value:"org.dbunit.database.ForwardOnlyResultSetTableFactory") } } 

有一个程序可以比较/减去两个CSV文件。 它使用ArrayList

 import java.io.*; import java.util.ArrayList; /* file1 - file2 = file3*/ public class CompareCSV { public static void main(String args[]) throws FileNotFoundException, IOException { String path="D:\\csv\\"; String file1="file1.csv"; String file2="file2.csv"; String file3="p3lang.csv"; ArrayList al1=new ArrayList(); ArrayList al2=new ArrayList(); //ArrayList al3=new ArrayList(); BufferedReader CSVFile1 = new BufferedReader(new FileReader(path+file1)); String dataRow1 = CSVFile1.readLine(); while (dataRow1 != null) { String[] dataArray1 = dataRow1.split(","); for (String item1:dataArray1) { al1.add(item1); } dataRow1 = CSVFile1.readLine(); // Read next line of data. } CSVFile1.close(); BufferedReader CSVFile2 = new BufferedReader(new FileReader(path+file2)); String dataRow2 = CSVFile2.readLine(); while (dataRow2 != null) { String[] dataArray2 = dataRow2.split(","); for (String item2:dataArray2) { al2.add(item2); } dataRow2 = CSVFile2.readLine(); // Read next line of data. } CSVFile2.close(); for(String bs:al2) { al1.remove(bs); } int size=al1.size(); System.out.println(size); try { FileWriter writer=new FileWriter(path+file3); while(size!=0) { size--; writer.append(""+al1.get(size)); writer.append('\n'); } writer.flush(); writer.close(); } catch(IOException e) { e.printStackTrace(); } }} 

http://p3lang.com/subtract-one-csv-from-another-in-java/

你提到检测“更新”行。 我想这意味着一行具有某种forms的身份,在更新后仍然存在。 也许单个列或复合列提供标识。 这是您个人需要整理和实施的实施细节,它只会为您的解决方案添加更多代码。

无论如何……数据库往往对使用set数据和从csv文件加载数据有很好的支持。 所有大型关系数据库都有很好的支持,可以轻松地将csv文件中的数据加载到表中。 此时,在两个表之间查找新行或修改的行是非常简单的SQL查询。

它显然不是一个纯粹的Java解决方案,但值得一提的是我认为。

我的建议是什么:

您可以读取文件以创建由其分隔的标记,并从两侧修剪每个标记,以便处理额外的空间,然后将它们存储在有序的数据结构中(类似于链接的哈希集,链接的哈希映射等)(如果你想在文件中传递重复项(如果有的话),然后为另一个文件重复它。

Java提供了许多实用方法来比较这些数据结构。 🙂