有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

比较Java中的两个csv文件

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

最好的方法是什么

注意:如果我们能知道第二个文件中有一行被更新、插入或删除,那就太好了

要求:-

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

共 (6) 个答案

  1. # 1 楼答案

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

  2. # 2 楼答案

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

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

    更新

    好的,你有一个PK字段。我假设你知道如何从你的字符串中得到它;使用openCSV或regex或任何你想要的东西。制作一个实际的HashMap而不是上面的HashSet,使用PK作为键,行作为值

    HashMap<String, String> f1 = new HashMap<String, String>();
    HashMap<String, String> f2 = new HashMap<String, String>();
    // read f1, f2; use PK field as the key
    List<String> deleted = new ArrayList<String>();
    List<String> updated = new ArrayList<String>();
    for(Map.Entry<String, String> 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
    
  3. # 3 楼答案

    有一个比较/减去两个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/

  4. # 4 楼答案

    您提到检测“更新”行。我猜这意味着一行在某种程度上有一个身份,可以在更新后生存。可能是单个列或复合列提供标识。这是您个人需要整理和实现的实现细节,它只会为您的解决方案添加更多代码

    无论如何。。。数据库往往能够很好地支持使用集合数据和从csv文件加载数据。所有大型关系数据库都提供了强大的支持,并提供了将csv文件中的数据加载到表中的简单语法。此时,在两个表之间查找新行或修改行是非常简单的sql查询

    这显然不是一个纯java解决方案,但我认为值得一提

  5. # 5 楼答案

    尝试使用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]]
    

    文件1。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
    

    文件2。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
    

    微分槽

    //
    // 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")
        }
    }
    
  6. # 6 楼答案

    如果您想要比较存储在字符串变量中的两个csv响应(如果您通过REST调用获得它们),我的简单解决方案是。在我的例子中,我想在10行不同的阈值之后退出检查

            BufferedReader baseline = new BufferedReader(new StringReader(responseBaseline));
            BufferedReader tested = new BufferedReader(new StringReader(responseTested));
            String lineBaseline = null;
            String lineTested = null;
            boolean linesExist = true;
            boolean foundDiff = false;
            int lineNumber = 0;
            int errorNumber = 0;
            int errorThreshold = 10;
            String message = "";
            while (linesExist) {
                try {
                    lineBaseline = baseline.readLine();
                    lineTested = tested.readLine();
                    lineNumber++;
                    if ((lineBaseline != null) && (lineTested != null)) {
                        if (!lineTested.equals(lineBaseline)) {
                            foundDiff = true;
                            errorNumber++;
                            if (errorNumber > errorThreshold) {
                                message = message + "\r\n" + "Found more than " + errorThreshold + " lines that were different. Will exit check.";
                                break;
                            }
                            message = message + "\r\n" + "\r\n#Found differences for line number " + lineNumber + "\r\nLine baseline: " + lineBaseline + "\r\nLine tested: " + lineTested;
                        }
                    } else {
                        linesExist = false;
                    }
                } catch (IOException e) {
                    throw new Error("Problems with reading csv files");
                }
            }
            if (foundDiff) {
                throw new Error("Found differences between csv files. " + message);
            }
        }