Оболочка Delphi TStringList для реализации сжатия на лету

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

Кто-нибудь знает потомка TStringlist, который реализует это, т.е. предоставляет доступ для чтения и записи к несжатым строкам, но сохраняет их внутренне сжатыми, так что TStringList.SaveToFile создает сжатый файл?

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

ТИА Росс


person rossmcm    schedule 13.07.2010    source источник
comment
Сжатые данные все равно необходимо распаковать, чтобы их можно было прочитать, и поэтому они по своей сути неэффективны. Если вам действительно нужно что-то для быстрого чтения в памяти, держите список ключей несжатым.   -  person Warren P    schedule 01.02.2011


Ответы (4)


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

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

Еще одна вещь, о которой вы, возможно, захотите прочитать, - это веревки - концептуально отличный от строк тип, который Я уже предлагал Марко Канту некоторое время назад. За счет следующего указателя на «шпагат» (из-за отсутствия лучшего слова) вы можете объединять части строки, не сохраняя никаких повторяющихся данных. Основная проблема заключается в том, как получить части, которые можно объединить в новую «веревку», представляющую вашу исходную строку. Как только эта проблема будет решена, вы сможете в любой момент реконструировать данные в виде строки, сохранив при этом компактное хранилище.

Если вы не хотите идти по «веревочному» маршруту, вы также можете попробовать так называемое «сокращение префикса», которое представляет собой простую форму сжатия - просто начинайте каждую строку с индекса предыдущей строки и количества символов. это следует рассматривать как префикс для новой строки. Имейте в виду, что вам не следует не возвращаться слишком далеко назад, иначе скорость доступа сильно пострадает. В одной простой реализации я сделал mod 16 в индексе, чтобы установить запись, с которой началось сокращение префикса, что дало мне в среднем около 40% экономии памяти (это число, конечно, полностью зависит от данных).

person PatrickvL    schedule 13.09.2010

Вы можете попробовать обернуть Delphi или COM API вокруг массивов Джуди. Тип JudySL подойдет, и у него довольно простой интерфейс.

РЕДАКТИРОВАТЬ: Я предполагаю, что вы храните уникальные строки и хотите (или рады) хранить их в лексикографическом порядке. Если эти ограничения неприемлемы, массивы Judy не для вас. Имейте в виду, что любая система сжатия пострадает, если вы не отсортируете свои строки.

person Marcelo Cantos    schedule 13.07.2010
comment
Разве Джуди не ассоциативный массив? Если действительно так, то это замена TDictionary ‹›, а не TStringList. И единственная ссылка, которую я нашел на JudySL, это следующее: judy.sourceforge.net/doc/JudySL_3x.htm - это не замена TStringList. - person Cosmin Prund; 13.07.2010
comment
Ага. Ой. Кросс-языковая оболочка в COM просто для использования структуры данных? Нет, спасибо. Но если бы кто-нибудь написал родной Pascal / Delphi JudyArray, я бы обязательно попробовал. - person Warren P; 01.02.2011

Я полагаю, вы ожидаете от списка общей гибкости (включая операцию удаления), в этом случае я не знаю ни одного нестандартного решения, но я бы предложил один из двух подходов:

  • Вы разбиваете свою строку на слова и сохраняете разделенный растущий словарь, чтобы ссылаться на слова и сохранять список индексов внутри

  • Вы реализуете что-то, связанное с потоком zlib, доступным в Delphi, но работающим с блоком, который, например, может содержать 10-100 строк. В этом случае вам все равно придется повторно сжать / сжать весь блок, но «цена», которую вы платите, будет ниже.

person Maksee    schedule 13.07.2010
comment
На самом деле мне не нужна такая гибкость. Если бы я извлекал список каталогов (скажем) из 10 000 000 файлов и имен путей и хотел бы сохранить их в сжатом виде, сработал бы первый подход, который вы упомянули. Мне просто было интересно, есть ли где-нибудь готовое решение. - person rossmcm; 13.07.2010

Я не думаю, что вы действительно хотите сжимать элементы TStrings в памяти, потому что это ужасно неэффективно. Предлагаю вам взглянуть на реализацию TStream в модуле Zlib. Просто оберните обычный поток в TDecompressionStream при загрузке и в TCompressionStream при сохранении (вы даже можете отправить туда заголовок gzip). Подсказка: вы захотите переопределить LoadFromStream / SaveToStream вместо LoadFromFile / SaveToFile

person Free Consulting    schedule 13.11.2010