Определение поведения GZIPOutputStream - PullRequest
0 голосов
/ 15 февраля 2020

Следующий код создает файлы, которые являются детерминированными c (shasum одинаков) для двух строк.

    try(
            FileOutputStream fos = new FileOutputStream(saveLocation);
            GZIPOutputStream zip = new GZIPOutputStream(fos, GZIP_BUFFER_SIZE);
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(zip, StandardCharsets.UTF_8));
            ){
        writer.append(str);
    }

Производит:

a.gz f0200d53f7f9b35647b5dece0146d72cd1c17949

Однако, если я возьму файл в командной строке и повторно заархивировать его, он дает другой результат

> gunzip -n a.gz ;gzip -n a ; shasum a.gz 

50f478a9ceb292a2d14f1460d7c584b7a856e4d9  a.gz

Как я могу получить его, чтобы соответствовать исходному ша, используя / usr / bin / gzip и gunzip?

1 Ответ

1 голос
/ 16 февраля 2020

Я думаю, что проблема, вероятно, заключается в заголовке файла Gzip.

  • В формате Gzip предусмотрено включение имени файла и метки времени файла в заголовки файлов. (Я вижу, что вы используете -n при распаковке и повторном сжатии ... что, вероятно, здесь правильно.)

  • Формат Gzip также включает в себя «идентификатор операционной системы» в заголовке , Это должно идентифицировать тип исходной файловой системы; например, 0 для FAT, 3 для UNIX и т. д.

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

Если Я собирался решить это сам, я начал бы с использования cmp, чтобы увидеть, где начинаются различия в сжатых файлах, а затем od, чтобы определить, в чем различия. Обратитесь к формату файла Gzip spe c, чтобы выяснить, что означают различия:

  • RF C 1952 - версия спецификации формата файла GZIP 4.3
  • Википедия gzip страница.

Как мне получить его, чтобы он соответствовал оригинальному SHA, используя gzip и gunzip?

Предполагая, что разница заключается в идентификаторе ОС, я не думаю, что есть практический способ решить это с помощью команд gzip и gunzip.


Я посмотрел исходный код для GZIPOutputStream в Java 11, и это не многообещающе.

  • Это жесткая привязка временной метки к нулю.
  • Это жесткая привязка идентификатора ОС к нулю (что должно означать FAT).

Жесткое подключение выполняется методом private, и его почти невозможно "исправить" с помощью подкласса или отражения. Вы можете скопировать код и исправить его таким образом, но тогда вам придется бесконечно поддерживать ваш вариант GZIPOutputStream class.

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

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