Вопрос по java – Сравнение двух CSV-файлов в Java

8

Нам нужно сравнить два CSV-файла. Допустим, у файла один есть несколько строк, а у второго файла может быть одинаковое количество строк или более. Большинство строк могут оставаться одинаковыми в обоих файлах. Ищем лучший способ провести различие между этими двумя файлами и читать только те строки, которые имеют отличие во втором файле от первого файла. Приложение, обрабатывающее файл, находится на Java.

Каковы лучшие подходы для этого?

Примечание: было бы здорово, если бы мы знали, что строка обновлена, вставлена или удалена во втором файле.

Требования:-

There won't be any duplicate records File 1 and file 2 could have same no of records with a few rows with updated values in file2 (Records updated) File 2 could have a few rows removed ( this is treated as record deleted) File 2 could have a few new rows added ( this is treated as record inserted) On of the column could be treated a the primary key of the record, that won't change in both the files.
Я ищу что-то похожее из этого постаstackoverflow.com/questions/9528202/… Java Guy
Могут ли файлы содержать повторяющиеся строки? Имеют ли они файлы одинаковые столбцы или столбцы одного файла являются подмножеством столбцов другого? G. Bach
Как бы вы определили «обновленный»? Есть ли идентификатор? Возможно, было бы хорошо уточнить эти предположения в вопросе с самого начала. beerbajay
Это все еще не совсем понятно, можете ли вы отредактировать свой вопрос, чтобы он был более конкретным? beerbajay
Дубликаты не возможны. Порядок многих не будет таким же. Во втором файле может быть то же самое количество строк без обновления, несколько обновленных строк, несколько удаленных строк или несколько новых добавленных строк. Нам нужно было бы подобрать все эти изменения, сравнив оба файла. Java Guy

Ваш Ответ

7   ответов
8

Один из способов сделать это - использовать Java.Set интерфейс; читать каждую строку как строку, добавить ее в набор, а затем сделатьremoveAll() со вторым набором на первом наборе, таким образом сохраняя строки, которые отличаются. Это, конечно, предполагает, что в файлах нет повторяющихся строк.

// 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

Update

Итак, у вас есть поле ПК. Я просто предположу, что вы знаете, как получить это из вашей строки; используйте openCSV или регулярное выражение или что угодно. Сделать реальный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
Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededcompareTo()Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededf1Error: User Rate Limit Exceededf2Error: User Rate Limit Exceededf1Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Я только что видел комментарий выше, и ОП сказал, что дубликаты в файле невозможны, так что вам там хорошо.
1

Есть программа, которая сравнивает / вычитает два 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/

0

Вы упомянули обнаружение "обновлено" строк. Я предполагаю, что это подразумевает, что строка каким-то образом переживает обновление. Может быть один столбец или составной столбец обеспечивает идентичность. Это детали реализации, которые вам лично нужно разобрать и реализовать, и это только добавит больше кода в ваше решение.

В любом случае ... базы данных имеют хорошую поддержку для работы с заданными данными и загрузки данных из CSV-файлов. Все реляционные базы данных с большим именем имеют отличную поддержку с простым синтаксисом для загрузки данных из CSV-файла в таблицу. На этом этапе поиск новых строк или измененных строк между двумя таблицами - это очень простые SQL-запросы.

это явно не чисто решение Java, но стоит упомянуть, я думаю.

-1

Что я предлагаю:

Вы можете прочитать файл, чтобы создать токены, разделенные и обрезать каждый токен с обеих сторон, чтобы позаботиться о дополнительных пробелах, а затем сохранить их в упорядоченной структуре данных (аналогично связанному хэш-набору, связанной хэш-карте и т. Д. ( если вы хотите передать дубликаты в файл (если они есть), а затем повторите их для другого файла.

Java предоставляет множество вспомогательных методов для сравнения этих структур данных. :)

3

Попробуйте использоватьJava-Diff-Utils библиотека

Example

Я использую 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
}

Update

СогласноFAQ по dbunit производительность этого решения может быть улучшена для очень больших наборов данных с помощью потоковой ревизии интерфейса 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")
    }
}
Java Guy
Error: User Rate Limit Exceededdbunit.org/faq.html#streaming
4

Прочитайте весь первый файл и поместите его вList, Затем читайте второй файл по одной строке за раз и сравнивайте каждую строку со всеми строками первого файла, чтобы определить, является ли он дубликатом. Если это не дубликат, то это новая информация. Если у вас проблемы с чтением, посмотрите наhttp://opencsv.sourceforge.net/Это довольно хорошая библиотека для чтения CSV-файлов на Java.

Error: User Rate Limit Exceeded Java Guy
0

Мое простое решение, если вы хотите сравнить два 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);
        }
    }

Похожие вопросы