Сравнить два файла java

Обновлено: 20.06.2024

Я пишу тест JUnit для некоторого кода, который создает файл Excel (который является двоичным). У меня есть другой файл Excel, который содержит мой ожидаемый вывод. Какой самый простой способ сравнить фактический файл с ожидаемым файлом?

Конечно, я мог бы написать код сам, но мне было интересно, есть ли существующий метод в доверенной сторонней библиотеке (например, Spring или Apache Commons), который уже делает это.

Вот что я в итоге сделал (с тяжелой работой, выполняемой DBUnit ):

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

Вы можете рассмотреть возможность использования моего проекта simple-Excel , который предоставляет кучу Hamcrest Matchers для выполнения этой работы.

Когда вы делаете что-то вроде следующего,

Вы бы увидели, например,

Таким образом, вы можете запустить его из своих автоматических тестов и получать значимые отзывы во время разработки.

Вы можете прочитать больше об этом на эта статья на моем сайте

Простое сравнение файлов можно легко выполнить с помощью некоторой контрольной суммы (например, MD5) или просто прочитав оба файла.

Однако, поскольку файлы Excel содержат множество метаданных, файлы, вероятно, никогда не будут идентичны побайтно, как указал Джеймс Берджесс. Таким образом, вам понадобится другой вид сравнения для вашего теста.

Я бы порекомендовал как-то сгенерировать "каноническую" форму из файла Excel, то есть прочитать сгенерированный файл Excel и преобразовать его в более простой формат (CSV или что-то подобное), который будет содержать только ту информацию, которую вы хотите проверить. Затем вы можете использовать "каноническую форму" для сравнения с ожидаемым результатом (также, конечно, в канонической форме).

Apache POI может быть полезно для чтения файла.

Кстати: чтение всего файла для проверки его корректности, как правило, не считается модульным тестом. Это интеграционный тест .

Мне нужно было сделать нечто подобное, и я уже использовал Apache POI library в моем проекте для создания файлов Excel. Поэтому я решил использовать включенный интерфейс ExcelExtractor для экспорта обеих книг в виде строки текста и утверждал, что строки равны. Существуют реализации как HSSF для .xlsx , так и XSSF для .xlsx .

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

Вы можете использовать javaxdelta, чтобы проверить, совпадают ли эти два файла. Это доступно здесь:

Я создаю серию видеоуроков для PACKT о сетевом программировании на Java. Существует целый раздел о Java NIO. Одним из примеров программы является копирование файла через необработанное сокетное соединение с клиента на сервер. Клиент читает файл с диска, а сервер сохраняет байты по мере их поступления на диск. Поскольку это демонстрационная версия, сервер и клиент работают на одном компьютере, и файл копируется из одного каталога в один и тот же каталог, но с другим именем. Доказательством того, что пудинг съест это: файлы нужно сравнивать.

Файл, который я хотел скопировать, был создан, чтобы содержать случайные байты. Передача только текстовой информации может иногда оставлять некоторую сложную ошибку в коде. Случайный файл был создан с использованием простого Java-класса:

public static void main(String[] args) throws IOException < try (FileOutputStream fos = new FileOutputStream( "sample.txt" )) <

Использовать IntelliJ для сравнения файлов довольно просто, но, поскольку файлы являются двоичными и большими, такой подход не совсем оптимален. Я решил написать короткую программу, которая будет не только сигнализировать, что файлы разные, но и где разница. Код очень прост:

public static void main(String[] args) throws IOException < BufferedInputStream fis1 = new BufferedInputStream( new FileInputStream( "sample.txt" )); BufferedInputStream fis2 = new BufferedInputStream( new FileInputStream( "sample-copy.txt" )); System.out.println( "Files are identical, you can delete one of them." ); System.out.print( "Execution time: " + (end - start)/ 1000000 + "ms" );

Время сравнения двух 160-мегабайтных файлов составляет около 6 секунд на моем Mac Book, оборудованном твердотельным накопителем, и оно значительно не улучшится, если я укажу большой, скажем, 10 МБ буфер в качестве второго аргумента для конструктора BufferedInputStream . (С другой стороны, если мы не используем BufferedInputStream тогда время примерно в десять раз больше.) Это приемлемо, но если я просто diff sample.txt sample-copy.txt из командной строки, то ответ значительно быстрее, а не 6 секунд. Это может быть много вещей, таких как время запуска Java, интерпретация кода в начале цикла while, пока JIT-компилятор не решит, что пора начинать работать. Однако я догадываюсь, что код тратит большую часть времени на чтение файла в память. Чтение байтов в буфер является сложным процессом. Это касается операционной системы, драйверов устройств, реализации JVM, и они перемещают байты из одного места в другое, и, наконец, мы сравниваем только байты, и ничего больше. Это можно сделать более простым способом. Мы можем попросить операционную систему сделать это для нас и пропустить большинство действий времени выполнения Java, файловых буферов и других проблем.

Мы можем попросить операционную систему прочитать файл в память, а затем просто извлечь байты один за другим, где они находятся. Нам не нужен буфер, который принадлежит объекту Java и использует пространство кучи. Мы можем использовать отображенные в память файлы. В конце концов, файлы с отображением в памяти используют Java NIO, и это как раз та часть той части обучающих видео, которая в настоящее время находится в стадии разработки.

IntelliJ IDEA предлагает множество способов сравнения файлов, папок и фрагментов кода и даже синхронизации содержимого папок.

Сравнение файлов проекта

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

Теперь у вас есть два варианта:

  1. Щелкните правой кнопкой мыши один из файлов и выберите в меню опцию «Compare Files».
  2. Нажмите Ctrl + D

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


Каждое отличие имеет цветовую кодировку:

  • Отсутствие окраски означает, что содержание одинаково
  • Синий означает наличие изменений в той же строке
  • Зеленый означает новый контент
  • Серый означает удаленный контент

Вы можете нажать иконки со стрелками » и «, чтобы применить конкретное изменение из одного файла в другой.

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

Сравнение с файлом вне проекта

Второй пример, когда вам нужно сравнить файл из вашего проекта с другим файлом вне его.

Процесс очень похож на описанный выше. Выберите один файл в окне вашего проекта и:

  1. Щелкните правой кнопкой мыши один из файлов и выберите в меню опцию «Compare With. »
  2. Нажмите Ctrl + D

Последний шаг — поиск внешнего файла для сравнения. Далее сравнение происходит так же, как и в примере выше.

Сравнение с буфером обмена

Возможно, у вас есть файл в вашем проекте, и вам нужно сравнить его с некоторым внешним контентом, который не сохраняется как файл на вашем компьютере. Может быть, это фрагмент кода из Интернета, например, с сайта stackoverflow.

Во-первых, вам нужно открыть файл из вашего проекта в вашем редакторе. Затем скопируйте в буфер обмена фрагмент, который вы хотите сравнить (Ctrl + C).

Теперь у вас есть два варианта. Либо сравните весь файл с буфером обмена, либо сравнить выделенный текст.

  1. Если вы хотите, чтобы весь файл сравнивался, просто щелкните правой кнопкой мыши в любом месте редактора и выберите «Compare with Clipboard» в контекстном меню.
  2. Если вы хотите сравнить только выделенный текст, сначала выберите какой-то фрагмент файла, а затем щелкните правой кнопкой мыши, как и раньше.

Собственное сравнение

Как насчет случая, когда вы хотите сравнить два фрагмента кода из внешних источников? Вы тоже можете это сделать! Просто запустите Find Action с помощью Ctrl + Shift + A и затем найдите опцию Open Blank Diff Window в контекстном меню.

Откроется новое окно сравнения с пустыми обеими панелями, так что вы сможете скопировать и вставить оба фрагмента для сравнения.

Сравнение с предыдущей локальной версией файла

Даже если вы не используете какую-либо систему контроля версий, IDEA хранит исторические версии ваших локальных файлов. Вы можете щелкнуть правой кнопкой мыши в вашем редакторе и выбрать Local history → Show history в контекстном меню.


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

Сравнить с использованием VCS

Если вы используете систему контроля версий (VCS), у вас есть еще несколько вариантов сравнения. Например, если вы используете Git, вы можете перейти к VCS → Git или щелкнуть правой кнопкой мыши на вашем редакторе и выбрать Git. Теперь вы можете:

  • Сравнить с той же версией репозитория: сравнивает текущий локальный файл с версией в вашем удаленном репозитории
  • Сравнить с веткой: сравнивает локальный файл с тем же файлом в другой ветке
  • Показать историю: сравнивает локальный файл с его предыдущими версиями

Сравнение папок

Сравнение работает не только для отдельных файлов, но и для целых каталогов. Процесс такой же, как и для файлов — просто выберите две папки в окне вашего проекта и нажмите Ctrl + D или щелкните правой кнопкой мыши и выберите Compare Directories в контекстном меню.


Здесь вы можете увидеть список всех файлов, присутствующих в обоих или в одном из каталогов. Вы можете легко определить, какие файлы присутствуют только в одной папке, а какие в обеих. Файлы в обоих папках вы можете сравнить, как обычно.

Синхронизация папок

Инструмент сравнения каталогов полезен не только для выявления различий в обоих каталогах, но и для синхронизации изменений. Вы можете применить изменения для отдельных разделов каждого файла, как обычно. Но вы также можете пометить файлы, присутствующие только в одном из каталогов, для сохранения или синхронизации с другим каталогом. Вы можете изменить желаемое действие для каждого файла в столбце *. Как только вы закончили свой выбор, вы можете нажать либо Synchronize selected, либо Synchronize all для выполения нейобходимой синхронизации.


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

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

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

  1. Не будет повторяющихся записей
  2. Файл 1 и файл 2 могут иметь одинаковое количество записей с несколькими строками с обновленными значениями в файле 2 (записи обновлены)
  3. Из файла 2 может быть удалено несколько строк (это считается удаленной записью)
  4. В файл 2 может быть добавлено несколько новых строк (это рассматривается как вставленная запись)
  5. Один из столбцов можно рассматривать как первичный ключ записи, который не изменится в обоих файлах.

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

Обновить

Итак, у вас есть поле PK. Я просто предполагаю, что вы знаете, как получить это из своей строки; используйте openCSV или регулярное выражение или что угодно. Сделать актуальный HashMap вместо HashSet как указано выше, используйте PK в качестве ключа и строку в качестве значения.

  • спасибо, Хасан. Да, opencsv - хороший вариант для чтения и сравнения. Я все еще ищу способ получить разницу на лету.

Попробуйте использовать библиотеку java-diff-utils

Я использую groovy для быстрой демонстрации java-библиотек:

Сообщается о следующих различиях между двумя файлами примеров:

files1.csv

file2.csv

diff.groovy

Согласно dbunit FAQ, производительность этого решения может быть улучшена для очень больших наборов данных с помощью потоковой версии интерфейса ResultSetTableFactory. Это включено в задаче ANT следующим образом:

Есть программа, которая сравнивает / вычитает два файла CSV. Он использует ArrayList

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

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

Мое простое решение на случай, если вы хотите сравнить два ответа csv, хранящиеся в строковых переменных (в случае, если вы получаете их через вызов REST). В моем случае я хотел выйти из проверки после порога в 10 разных строк.

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

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

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

Читайте также: