Форматы сжатия с хорошей поддержкой произвольного доступа в архивах?

Это похоже на предыдущий вопрос, но ответы там не удовлетворяют мои потребности, и мой вопрос немного отличается:

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

Но когда файлы сжимаются, все усложняется. Недавно я узнал о параметре Z_FULL_FLUSH zlib, который можно использовать во время сжатия для вставки «точек синхронизации» в сжатый вывод (затем inflateSync() может начать чтение из различных точек файла). Это нормально, хотя файлы, которые у меня уже есть, должны быть повторно сжаты, чтобы добавить эту функцию (и, как ни странно, gzip не имеет для этого возможности, но я готов написать свою собственную программу сжатия, если нужно).

Похоже, из один источник, что даже Z_FULL_FLUSH не является идеальным решением ... он не только не поддерживается всеми архивами gzip, но и сама идея обнаружения точек синхронизации в архивах может давать ложные срабатывания (либо по совпадению с магическим числом для точек синхронизации или из-за того, что Z_SYNC_FLUSH также создает точки синхронизации, но они не могут использоваться для произвольного доступа).

Есть ли лучшее решение? Я бы хотел по возможности избегать использования вспомогательных файлов для индексации, и явная поддержка по умолчанию для квазислучайного доступа была бы полезной (даже если она крупномасштабная - например, возможность начинать чтение через каждые 10 МБ). Есть ли другой формат сжатия с лучшей поддержкой случайного чтения, чем gzip?

Изменить. Как я уже упоминал, я хочу выполнять двоичный поиск в сжатых данных. Мне не нужно искать конкретную (несжатую) позицию - только для поиска с некоторой грубой степенью детализации внутри сжатого файла. Мне просто нужна поддержка чего-то вроде «Распакуйте данные, начиная примерно с 50% (25%, 12,5% и т.д.) пути в этот сжатый файл».


person John Zwinck    schedule 09.01.2009    source источник


Ответы (13)


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

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

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

person jpalecek    schedule 09.01.2009
comment
Мне не нужно искать конкретную несжатую позицию - только для поиска несколько случайным образом с некоторой грубой степенью детализации внутри сжатого файла. Я совсем не возражаю, если все, что я могу сделать, это сказать, что данные отсюда не соответствуют требованиям, около 700 МБ в этот файл. - person John Zwinck; 10.01.2009
comment
@John Zwinck: Добавьте свой комментарий к своему вопросу в качестве обновления. Обратите внимание, что, учитывая переменное сжатие данных (некоторые вещи, которые я сжимаю, сжимаются на 94% или около того - обычно, за исключением случаев, когда они сжимаются примерно на 50% или около того), ваша оценка того, с чего начать распаковку, может быть очень ошибочной. - person Jonathan Leffler; 10.01.2009
comment
Просто примечание, которое усложняется тем, что границы блока bzip2 находятся в пределах байта, поэтому это выполнимо, но требуется больше бухгалтерского учета. - person Alex Reynolds; 30.01.2015

Взгляните на dictzip. Он совместим с gzip и допускает грубый произвольный доступ.

Выдержка из его справочной страницы:

dictzip сжимает файлы с помощью алгоритма gzip (1) (LZ77) способом, полностью совместимым с форматом файлов gzip. Расширение формата файла gzip (дополнительное поле, описанное в 2.3.1.1 RFC 1952) позволяет хранить дополнительные данные в заголовке сжатого файла. Такие программы, как gzip и zcat, игнорируют эти дополнительные данные. Однако [dictzcat --start] будет использовать эти данные для выполнения псевдослучайного доступа к файлу.

У меня есть пакет dictzip в Ubuntu. Или его исходный код находится в dictd - *. Tar.gz. Его лицензия - GPL. Вы можете изучать его.

Обновлять:

Я улучшил dictzip, чтобы не было ограничений на размер файла. Моя реализация находится под лицензией MIT.

person Ivo Danihelka    schedule 24.10.2010
comment
Я решил свою проблему с помощью точек синхронизации / сброса gzip, которые позволяют мне легко сканировать файл (выполняя двоичный поиск). Мне пришлось написать свою собственную программу, похожую на gzip, поверх libz, потому что стандартный gzip по какой-либо причине не включает средства для записи точек синхронизации. В любом случае, в моем случае это отлично работает, потому что меня не волнует возможность чтения, начиная с байта 10000, а только для чтения, начиная примерно с 50% пути через файл. Подход dictzip действительно выглядит очень интересным и решает, возможно, более общую проблему, чем моя. - person John Zwinck; 06.11.2010
comment
Правильно ли я понимаю, что вы использовали исходный код под лицензией GPL в качестве основы для своей лицензионной программы MIT? Это нарушение лицензии GPL! - person Jacek Kaniuk; 15.04.2014
comment
@JacekKaniuk Извините, что сбил вас с толку. Спецификация формата файла dictzip была использована и заново реализована на Python. - person Ivo Danihelka; 16.04.2014
comment
@JohnZwinck Вы упомянули ложные срабатывания как потенциальную проблему. Вы это решили? Я предполагаю, что ваше решение было в c? Похоже, мне нужна точно такая же функциональность, любые советы или код будут оценены. - person TJez; 05.09.2014
comment
@TroyJ: если вы контролируете запись файлов, ложные срабатывания будут происходить не часто, и когда они это сделают, вы можете знать об этом, потому что декомпрессия из этих точек не удастся (и вы можете попробовать еще раз). Если вы не контролируете запись, все становится сложнее: стандартные программы записи gzip будут выдавать много ложных срабатываний и не будут давать истинных срабатываний. Вы можете повторить попытку N раз, прежде чем сдаться; по моему опыту, N должно быть небольшим числом (меньше 10), чтобы система была достаточно точной. - person John Zwinck; 05.09.2014
comment
Где документация? Могу ли я использовать dictzip для чтения последней строки моего файла, если я знаю либо байтовую позицию начала последней строки в несжатом файле, либо общее количество строк? Это потенциально очень круто! Позволяет ли это индексировать сжатый файл tabix, как это было бы возможно с файлом bgzipped? - person tommy.carstensen; 30.01.2015
comment
Я написал stdio-подобную библиотеку и утилиту многопоточного сжатия. Исходники доступны на github: github.com/hoxnox/csio - person hoxnox; 18.06.2015
comment
@hoxnox - разрешает ли ваша утилита csio произвольное чтение уже существующих данных, сжатых с помощью gzip, или только данные, сжатые с помощью gzip, созданные csio? - person Adam Katz; 02.12.2015
comment
@JohnZwinck - похоже, вы решили проблему. Могли бы поделиться своим кодом? - person Adam Katz; 02.12.2015
comment
@AdamKatz: Я не могу поделиться кодом, отчасти потому, что он тесно интегрирован с проприетарным форматом данных, поэтому никто бы не стал использовать его напрямую. Однако идея состоит в том, чтобы записывать точки полной синхронизации время от времени при сжатии (скажем, один раз на МБ), а затем заставлять ваш читатель сканировать эти точки и проверять, имеют ли сообщения смысл при распаковке. Трудности в основном заключаются в следующем: (1) стандартный инструмент gzip вообще не имеет возможности вставлять точки полной синхронизации, (2) вам нужно написать собственную эвристику для проверки правильности сообщений при возобновлении. - person John Zwinck; 03.12.2015
comment
@AdamKatz - сжатые данные, созданные csio или dictzip - person hoxnox; 03.12.2015

Формат файла .xz (который использует сжатие LZMA), похоже, поддерживает это:

Чтение с произвольным доступом: данные можно разделить на независимо сжатые блоки. Каждый файл .xz содержит индекс блоков, что делает возможным ограниченное чтение с произвольным доступом, когда размер блока достаточно мал.

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

person AardvarkSoup    schedule 03.05.2014
comment
Да, это используется, например, pixz для произвольного доступа к элементам архивов tar или nbdkit для доступа к сжатым файлам xz как устройствам nbd (например, для возможности монтировать сжатые образы дисков). qcow2 (собственный формат для образов дисков qemu) - еще один формат, допускающий сжатие и произвольный доступ. - person Stephane Chazelas; 02.06.2016

Существуют решения для предоставления произвольного доступа к архивам gzip и bzip2:

(Я ищу что-то для 7zip)

person hippietrail    schedule 17.12.2010
comment
Я с интересом прочитал код Зрана, особенно учитывая, что он был написан Марком Адлером. Но, похоже, это всего лишь удобный механизм: в комментариях говорится, что сначала он считывает весь файл и создает индекс, который позже используется для выполнения произвольного доступа. Это, вероятно, отлично подходит для GhostScript, где, как я полагаю, входные файлы имеют порядок мегабайт. Но мои входные файлы имеют порядок гигабайт, поэтому читать их полностью перед выполнением произвольного доступа не так уж и хорошо. Хуже того, мой самый распространенный вариант использования - это один случайный доступ к открытому файлу. - person John Zwinck; 18.12.2010
comment
Да, безусловно, есть сопутствующие расходы. Это наиболее эффективно, если вы хотите использовать один и тот же архив много раз в течение длительного периода времени. - person hippietrail; 01.10.2013
comment
Ссылки мертвы. - person SOFe; 08.12.2020
comment
@SOFe: Спасибо. Я нашел свежие ссылки и обновил ответ. - person hippietrail; 08.12.2020

bgzip может сжимать файлы в gzip варианте, который индексируется (и может быть распакован с помощью gzip). Он используется в некоторых приложениях биоинформатики вместе с индексатором tabix.

См. Объяснения здесь: http://blastedbio.blogspot.fr/2011/11/bgzf-blocked-bigger-better-gzip.html, а здесь: http://www.htslib.org/doc/tabix.html.

Я не знаю, насколько он адаптируется к другим приложениям.

person bli    schedule 04.02.2016

Доступ к формату gzip можно получить случайным образом при условии, что индекс был ранее создан, как это показано на zran.c исходный код zlib.

Я разработал инструмент командной строки на основе zran.c zlib, который создает индексы для файлов gzip: https://github.com/circulosmeos/gztool

Он может даже создать индекс для все еще растущего файла gzip (например, журнала, созданного rsyslog непосредственно в формате gzip), тем самым сокращая на практике время создания индекса до нуля. См. Параметр -S (Наблюдать).

person circulosmeos    schedule 24.07.2019

Я не уверен, будет ли это практичным в вашей конкретной ситуации, но не могли бы вы просто сжать каждый большой файл на файлы меньшего размера, скажем, по 10 МБ каждый? В результате вы получите кучу файлов: file0.gz, file1.gz, file2.gz и т. Д. На основе заданного смещения в пределах исходного размера вы можете искать в файле с именем "file" + (offset / 10485760) + ".gz". Смещение в несжатом архиве будет offset % 10485760.

person William Brendel    schedule 09.01.2009
comment
Или вы можете TAR их всех и получить .GZ.TAR. :) - person Vilx-; 10.01.2009
comment
Это определенно сделало бы вещи чище. Я просто пытался упростить здесь, но ваше предложение хорошо принято :-) - person William Brendel; 10.01.2009
comment
.gz.tar на самом деле не является произвольным доступом, так как вы должны перепрыгивать через все заголовки, чтобы добраться до одного файла. - person jpalecek; 10.01.2009
comment
Ну и да, и нет. С фрагментами фиксированного размера (в данном случае 10 МБ) вам не придется просматривать список заголовков. Это основано на предположении, что tar упорядочит файлы в алфавитном порядке (что случается в GNU-land). - person William Brendel; 10.01.2009
comment
Да, но тогда файлы не будут сжаты (10 МБ без сжатия для работы вашего выражения индексации, 10 МБ со сжатием для прямого доступа в tar для работы). Трудно сжать что-либо до фиксированного размера, хотя вы можете сделать этот размер достаточно большим и обрабатывать лишнее пространство с помощью разреженных файлов. - person jpalecek; 10.01.2009
comment
Если вы хотите, чтобы различные файлы фрагментов были упакованы в один архив, вы можете просто использовать формат архива, например .zip, который поддерживает каталог, позволяющий произвольный доступ к отдельным файлам. Ключевая идея Уильяма Бренделя - разбить исходный файл на части и сжать их независимо. - person Michael Burr; 10.01.2009
comment
Это похоже на то, что делает сжатие Windows NTFS, чтобы разрешить произвольный доступ к данным - каждый кластер (или блок размером 2 КБ, или какой-либо блок) сжимается независимо. - person Michael Burr; 10.01.2009
comment
Мне не нужно много отдельных файлов (у меня их и так много!). Идея tar интересна, но я не уверен, что хочу иметь второй тип контейнера в каждом файле (мне пришлось бы написать код, который обрабатывает tar и untar ... что выполнимо, хотя и не совсем то, к чему я стремился. - person John Zwinck; 10.01.2009
comment
Все, кто указывал, что хранение файлов в архиве может нарушить произвольный доступ: вы правы. Я не думал :-) Я уберу этот пункт из своего ответа. Спасибо за наблюдения. - person William Brendel; 10.01.2009

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

Вы можете посмотреть «Сжатие: ключ к системам поиска текста нового поколения» Нивио Зивиани, Эдлено Сильва де Моура, Гонсало Наварро и Рикардо Баеза-Йейтс в журнале Computer, ноябрь 2000 г. http://doi.ieeecomputersociety.org/10.1109/2.881693

Их декомпрессор берет 1, 2 или 3 целых байта сжатых данных и распаковывает (используя список словаря) в целое слово. Можно напрямую искать в сжатом тексте слова или фразы, что оказывается даже быстрее, чем поиск в несжатом тексте.

Их декомпрессор позволяет указать на любое слово в тексте обычным (байтовым) указателем и немедленно начать распаковку с этой точки.

Вы можете присвоить каждому слову уникальный двухбайтовый код, поскольку в вашем тексте, вероятно, меньше 65 000 уникальных слов. (В Библии KJV почти 13 000 уникальных слов). Даже если имеется более 65 000 слов, довольно просто назначить первые 256 двухбайтовых кодовых «слов» всем возможным байтам, так что вы можете составить слова, которых нет в лексиконе 65 000 или около того «наиболее часто встречающихся» слова и фразы". (Сжатие, достигаемое за счет упаковки частых слов и фраз в два байта, обычно стоит «расширения», когда иногда пишется слово с использованием двух байтов на букву). Существует множество способов подобрать словарный запас «часто встречающихся слов и фраз», которые обеспечат адекватное сжатие. Например, вы можете настроить компрессор LZW, чтобы выгружать «фразы», ​​которые он использует более одного раза, в файл словаря, по одной строке на фразу, и запускать его по всем вашим данным. Или вы можете произвольно разделить несжатые данные на 5-байтовые фразы в файле словаря, по одной строке на фразу. Или вы можете разделить несжатые данные на настоящие английские слова и поместить каждое слово - включая пробел в начале слова - в файл словаря. Затем используйте команду «sort --unique», чтобы удалить повторяющиеся слова в этом файле лексики. (Выбор идеального "оптимального" словарного списка по-прежнему считается непростой задачей?)

Сохраните лексикон в начале вашего огромного сжатого файла, дополните его до некоторого удобного размера BLOCKSIZE, а затем сохраните сжатый текст - серию двухбайтовых «слов» - оттуда до конца файла. Предположительно, поисковик прочитает этот лексикон один раз и сохранит его в каком-либо формате для быстрого декодирования в ОЗУ во время распаковки, чтобы ускорить распаковку «двухбайтового кода» в «фразу переменной длины». Мой первый черновик будет начинаться с простого списка фраз по одной строке, но позже вы можете переключиться на хранение лексики в более сжатой форме, используя какое-то инкрементное кодирование или zlib.

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

person Community    schedule 07.08.2010

Два возможных решения:

  1. Позвольте ОС заниматься сжатием, создавать и монтировать сжатую файловую систему (SquashFS, clicfs, cloop, cramfs, e2compr или что-то еще), содержащую все ваши текстовые файлы, и ничего не делать со сжатием в вашей прикладной программе.

  2. Используйте клики непосредственно в каждом текстовом файле (по одному клику на текстовый файл) вместо сжатия образа файловой системы. Думайте о «mkclicfs mytextfile mycompressedfile» как о «gzip‹ mytextfile ›mycompressedfile», а «clicfs mycompressedfile directory» как о способе получения произвольного доступа к данным через файл «directory / mytextfile».

person Joachim Wagner    schedule 10.02.2012
comment
Вау, интересные мысли по моему старому вопросу. Ваше первое предложение (squashfs) не совсем то, что я хотел бы, потому что оно имеет последствия для удаленного хранилища: используя сжатую файловую систему и сжатые соединения SSH, вам удастся распаковать данные и повторно сжать их для отправки по сети. Что было бы замечательно, было бы что-то вроде сжатой файловой системы, которую можно было бы использовать через NFS. Я думаю, это то, что может дать ваше предложение clicfs. Документацию по clicfs найти довольно сложно (по крайней мере, при моем быстром поиске), но это многообещающе. Спасибо. - person John Zwinck; 11.02.2012
comment
Судя по информации в исходном вопросе, SquashFS - это именно то, что вы просите. Конечно, было бы идеально, если бы вам не приходилось распаковывать и повторно сжимать по сети, но если ваша SquashFS настроена с использованием алгоритма быстрой распаковки, то общая стоимость распаковки + сжатия предположительно будет незначительной. - person malthe; 07.03.2019

Это очень старый вопрос, но похоже, что zindex может предоставить хорошее решение (хотя у меня нет большой опыт с этим)

person robochat    schedule 04.09.2015

Я не знаю, упоминалось ли об этом, но проект Kiwix проделал большую работу в в этом отношении. Через свою программу Kiwix они предлагают произвольный доступ к файловым архивам ZIM. Сжатие тоже хорошее. Проект возник, когда возник спрос на офлайн-копии Википедии (который достиг более 100 ГБ в несжатом виде, включая все носители). Они успешно взяли файл размером 25 ГБ (однофайловый вариант Википедии без большинства носителей) и сжали его в жалкий zim-архив размером 8 ГБ. А с помощью программы Kiwix вы можете вызвать любую страницу Википедии со всеми связанными данными быстрее, чем при серфинге в сети.

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

person CogitoErgoCogitoSum    schedule 08.04.2013

razip поддерживает произвольный доступ с лучшей производительностью, чем gzip / bzip2, которые необходимо настроить для этой поддержки - уменьшение сжатия за счет "ok" произвольного доступа:

http://sourceforge.net/projects/razip/

person Erik Aronesty    schedule 23.08.2011
comment
Вы им пользовались? Насколько я понимаю, это похоже на мертвый проект. - person John Zwinck; 24.08.2011

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

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

Исходный код доступен на нашем сайте GitHub. Мы скомпилировали его под Linux и Mac OS X.

В вашем случае вы можете хранить (10 МБ или что-то еще) смещения в заголовке в настраиваемом формате архива. Вы анализируете заголовок, извлекаете смещения и постепенно fseek через файл с помощью current_offset_sum + header_size.

person Alex Reynolds    schedule 26.10.2011
comment
Обновлена ​​ссылка на сайт Github. - person Alex Reynolds; 30.01.2015
comment
BEDOPS также представляет новый формат сжатия без потерь под названием Starch, который уменьшает полногеномные наборы данных BED до ~ 5% от их исходного размера (и наборы данных BAM примерно до 35% от их исходного размера) ‹- Это потрясающе. Вы должны рекламировать свой инструмент. - person tommy.carstensen; 30.01.2015
comment
Мы написали статью: bioinformatics.oxfordjournals.org/content/28/14/1919 .abstract - person Alex Reynolds; 30.01.2015
comment
Samtools faidx не сжимается так же хорошо, как Starch, и требует хранения второго файла с геномными данными, но он предлагает более тонкую индексацию и поэтому более популярен. Крахмал действительно хорошо работает, если вам нужно сжать пространство или вы выполняете работу с полным геномом и хотите распараллелить задачи по хромосомам. Я работаю над Starch 2, который будет предлагать интервальные запросы базового уровня, но это может произойти через несколько месяцев. - person Alex Reynolds; 30.01.2015
comment
Сжатие бац до 35% даже лучше формата впихнуть. Я должен читать газету дома. Не могу поверить, что это широко не используется. - person tommy.carstensen; 30.01.2015