Сравните 2 текстовых файла в java и запишите разницу в обоих отдельно в другой файл - PullRequest
0 голосов
/ 26 апреля 2018

Это код, который я написал для выполнения механизма проверки для сравнения 2 файлов. Я хочу знать, есть ли способ написать это более продуктивно, потому что оба моих файла могут содержать миллионы записей, и я считаю, что в этих случаях это будет медленно.

Я думаю о добавлении хэш-карты, каждый раз, когда я получаю вхождение строки в файле, я добавляю +1 к значению ключа. Если нет, значение ключа остается 1. Если запись существует в другой карте файла 2, я удаляю ее из первой карты. Если этого не произойдет, то я добавлю его на карту. Это идет чередование файлов до конца.

Я не делаю построчное сравнение, потому что порядок строк в обоих файлах может быть разным.

public static void main(String[] args) throws Exception {
    BufferedReader br1 = null;
    BufferedReader br2 = null;
    BufferedWriter br3 = null;
    String sCurrentLine;
    int linelength;
    List<String> list1 = new ArrayList<String>();
    List<String> list2 = new ArrayList<String>();
    List<String> unexpectedrecords = new ArrayList<String>();

    br1 = new BufferedReader(new FileReader("expected.txt"));

    br2 = new BufferedReader(new FileReader("actual.txt"));

    while ((sCurrentLine = br1.readLine()) != null) {
        list1.add(sCurrentLine);
    }
    while ((sCurrentLine = br2.readLine()) != null) {
        list2.add(sCurrentLine);
    }
    List<String> expectedrecords = new ArrayList<String>(list1);

    List<String> actualrecords = new ArrayList<String>(list2);

    if (expectedrecords.size() > actualrecords.size()) {
        linelength = expectedrecords.size();
    } else {
        linelength = actualrecords.size();
    }

    for (int i = 0; i < linelength; i++) {
        if (actualrecords.contains(expectedrecords.get(i))) {
            actualrecords.remove(expectedrecords.get(i));
        } else {
            unexpectedrecords.add(actualrecords.get(i));
        }
    }

    br3 = new BufferedWriter(new FileWriter(new File("c.txt")));
    br3.write("Records which are not present in actual");
    for (int x = 0; x < unexpectedrecords.size(); x++) {
        br3.write(unexpectedrecords.get(x));
        br3.newLine();
    }
    br3.write("Records which are in actual but no present in expected");
    for (int i = 0; i < actualrecords.size(); i++) {
        br3.write(actualrecords.get(i));
        br3.newLine();
    }
    br3.flush();
    br3.close();
}

Ответы [ 3 ]

0 голосов
/ 26 апреля 2018

В Java 8 вы можете использовать Collection.removeIf(Predicate<T>)

list1.removeIf(line -> list2.contains(line));
list2.removeIf(line -> list1.contains(line));

list1 будет содержать все, что НЕ в list2, а list2 будет содержать все, что НЕ в list1.

0 голосов
/ 26 апреля 2018

Решение HashMap

Я думал об этом, и решение HashMap является мгновенным. Я пошел дальше и кодировал пример этого здесь.

Он запускается за 0 мс, в то время как arrayLists выполнялся за 16 мс для того же набора данных

public static void main(String[] args) throws Exception {
    BufferedReader br1 = null;
    BufferedReader br2 = null;
    BufferedWriter bw3 = null;
    String sCurrentLine;
    int linelength;

    HashMap<String, Integer> expectedrecords = new HashMap<String, Integer>();
    HashMap<String, Integer> actualrecords = new HashMap<String, Integer>();

    br1 = new BufferedReader(new FileReader("expected.txt"));
    br2 = new BufferedReader(new FileReader("actual.txt"));

    while ((sCurrentLine = br1.readLine()) != null) {
        if (expectedrecords.containsKey(sCurrentLine)) {
            expectedrecords.put(sCurrentLine, expectedrecords.get(sCurrentLine) + 1);
        } else {
            expectedrecords.put(sCurrentLine, 1);
        }
    }
    while ((sCurrentLine = br2.readLine()) != null) {
        if (expectedrecords.containsKey(sCurrentLine)) {
            int expectedCount = expectedrecords.get(sCurrentLine) - 1;
            if (expectedCount == 0) {
                expectedrecords.remove(sCurrentLine);
            } else {
                expectedrecords.put(sCurrentLine, expectedCount);
            }
        } else {
            if (actualrecords.containsKey(sCurrentLine)) {
                actualrecords.put(sCurrentLine, actualrecords.get(sCurrentLine) + 1);
            } else {
                actualrecords.put(sCurrentLine, 1);
            }
        }
    }

    // expected is left with all records not present in actual
    // actual is left with all records not present in expected
    bw3 = new BufferedWriter(new FileWriter(new File("c.txt")));
    bw3.write("Records which are not present in actual\n");
    for (String key : expectedrecords.keySet()) {
        for (int i = 0; i < expectedrecords.get(key); i++) {
            bw3.write(key);
            bw3.newLine();
        }
    }
    bw3.write("Records which are in actual but not present in expected\n");
    for (String key : actualrecords.keySet()) {
        for (int i = 0; i < actualrecords.get(key); i++) {
            bw3.write(key);
            bw3.newLine();
        }
    }
    bw3.flush();
    bw3.close();
}

например:

expected.txt

one
two
four
five
seven
eight

actual.txt

one
two
three
five
six

c.txt

Records which are not present in actual
four
seven
eight
Records which are in actual but not present in expected
three
six

ex 2:

expected.txt

one
two
four
five
seven
eight
duplicate
duplicate
duplicate

actual.txt

one
duplicate
two
three
five
six

c.txt

Records which are not present in actual
four
seven
eight
duplicate
duplicate
Records which are in actual but not present in expected
three
six
0 голосов
/ 26 апреля 2018

На компьютерах Unix / Linux вы можете просто позвонить diff, который был оптимизирован для скорости и использования памяти.

Звонок выглядит как

String listFileDiffs = executeDiff(filenameWithPath1, filenameWithPath2);

Способ реализован:

private String executeDiff(String filenameWithPath1, String filenameWithPath2) {
    StringBuffer output = new StringBuffer();
    Process p0;
    Process p1;
    Process p2;
    try {
        p0 = Runtime.getRuntime().exec("sort " + filenameWithPath1 + " > /tmp/sort1file");
        p0.waitFor();
        p1 = Runtime.getRuntime().exec("sort " + filenameWithPath2 + " > /tmp/sort2file");
        p1.waitFor();
        p2 = Runtime.getRuntime().exec("diff " + "/tmp/sort1file" + " " + "/tmp/sort2file");
        p2.waitFor();
        BufferedReader reader =
                new BufferedReader(new InputStreamReader(p2.getInputStream()));
        String line = "";
        while ((line = reader.readLine())!= null) {
            output.append(line + "\n");
        }
    } catch (Exception e) {
        LOG.error("Error: executeCommand ", e);
    }
    return output.toString();
}

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

Решение было адаптировано для учета случайного порядка строк в каждом файле. Unix sort вызывается для каждого из двух файлов. diff впоследствии запускается.

Команды Unix развивались десятилетиями и работают с высокой эффективностью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...