Возобновление неудачного сжатия с использованием Java - PullRequest
2 голосов
/ 28 июля 2010

У меня есть небольшое количество (2-10) больших файлов (6-15 ГБ), которые сжимаются очень хорошо (4: 1).

Я пишу клиент и сервер на Java и хочу отправить файлы с клиента на сервер, чтобы 1. клиент сжимает файлы по мере их отправки (т.е. промежуточный файл .zip не создается)
2. Сжатый материал на сервере заканчивается как правильно сформированный файл (например, файл .zip или .tgz), так что его можно загрузить «как есть».
3. перевод может быть возобновлен, если он не проходит в середине
4. возобновленная передача может вообще произойти в новом процессе

Первые два могут быть легко достигнуты с помощью сокетов java.io и java.util.zip ZipOutputStreams. Третий - тот, который вызывает у меня горе. Четвертый действительно контекст.

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

Существуют ли библиотеки Java, поддерживающие возобновляемое сжатие?

Ответы [ 3 ]

2 голосов
/ 31 июля 2010

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

Идея похожа на идеи разбиения на части, изложенные выше, но сервер управляет разбиением на блоки и выполняет некоторую бухгалтерию, которая отображает сжатыечанки на клиенте к сжатым чанкам на сервере.В решении нет временных файлов.Базовый протокол выглядит следующим образом:

(1) The client sends a manifest to the server, containing the
    to-be contents of the zip file  
(2) The server sends back an ID for the manifest  
    Then repeatedly  
  (3) The client asks the server "is there anything still 
      required for the manifest with ID X"
  (4) The server replies "no", or with a manifest entry 
      for a file in the manifest, plus a offset and length to send
  (5) The client compresses that chunk and sends it (plus some 
       bookkeeping info)
  (6) The server puts the chunk into the every growing zip file, 
      plus appropriate zip file crud. If the server orders 
      the chunks it asks the client for appropriately, this can 
      all be done by file appends.

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

Есть несколько битов, которые были немного сложными при создании кускового zip-файла.Основная вещь, которая должна быть достигнута, состоит в том, чтобы найти алгоритм сжатия, способный к фрагментам.Таким образом можно использовать Deflate.

java ZipOutputStream и DeflaterOutputStream не очень подходят для дефляции / архивирования по частям, поскольку они не допускают произвольного сброса.Существует лицензионная реализация ZLib в стиле BSD в стиле http://www.jcraft.com/jzlib.. Я не тестировал ее по скорости, но она дает тот же результат, что и реализация Java.JZLib великолепен и поддерживает все режимы очистки ZLib (в отличие от реализации java.util.zip.Deflate).

Кроме того, файлы Zip вычисляют CRC для каждой записи.Таким образом, запись манифеста на шаге 4 содержит «частичный» CRC, который для каждого чанка обновляется и отправляется обратно в информацию бухгалтерского учета на шаге 5. Существует общедоступная реализация CRC для Java на http://www.axlradius.com/freestuff/CRC32.java. Я тестировал его, и он так же быстр (и предоставляет эквивалентные CRC) нативную реализацию Java.

Наконец, формат Zip-файла довольно привередливый.Мне удалось собрать воедино большую часть реализации со страницы википедии и http://www.pkware.com/documents/casestudies/APPNOTE.TXT. Хотя в какой-то момент я не смог найти правильное значение для одного из полей.К счастью, JDK-источник ZipOutputStream доступен, чтобы вы могли видеть, что они делают.

0 голосов
/ 28 июля 2010

Сжатие на лету легко.Проблема, с которой вы столкнетесь, - возобновление загрузки.Это в основном исключает HTTP как транспорт, поэтому вам нужно взглянуть на что-то вроде (S) FTP или SCP.Даже там проблема в том, что вы не создаете файл на клиенте, так что же будет возобновлено?По крайней мере, вам нужно будет использовать метод сжатия, который является детерминированным (имеется в виду, что при заданном файле любые два прогона алгоритма сжатия будут давать абсолютно одинаковые выходные данные).Если это не так, вы не можете возобновить вообще .

Мой совет - слегка тангенциальный подход.Разделите файл на управляемые куски (скажем, 50 МБ).Это детерминистично.Сжатие каждого куска в отдельности.Если кусок не удается, отправьте его повторно.Возобновление не возобновляется, но вы можете получить частичные загрузки сервером, сообщая клиенту, какие куски он получил или ожидает.

Одна из проблем, с которой вы столкнетесь, - это идентификация конкретного файла.Будет ли имя файла делать?Есть ли какая-то другая идентификационная характеристика?Если два клиента попытаются загрузить один и тот же файл, сможет ли сервер это обнаружить?Стандартный подход для такого рода вещей заключается в использовании контрольной суммы (SHA1-хэш содержимого файла), но вы не хотите читать файл размером 16 ГБ целиком, просто чтобы выполнить контрольную сумму.Поэтому предпочтительнее использовать другой метод.

Представьте, что сетевое взаимодействие происходит примерно так:

Client: SEND file1234 CHUNKS 167
Server: RECEIVED (already got) or WAIT 7 (chunk #)
Client: compress and send chunk 7
Server: WAIT 8
....

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

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

0 голосов
/ 28 июля 2010

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

Вместо этого вы можете рассмотреть возможность «разбить» файл на более мелкие куски и отправить их по отдельности (со сжатием). Скажем, 100kb кусков (например). Вы все еще не можете возобновить работу с середины фрагмента, но вы можете легко начать с начала самого последнего фрагмента.

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