Доброго времени суток, уважаемый читатель! Эта статья представляет собой небольшой технический тутор по программированию с использованием библиотеки libbzip2, на базе которой создана популярная утилита bzip2. Если ты
начинающий UNIX/Windows-программист на сях и/или хочешь расширить свой кругозор, овладев удобным и компактным API для сжатия данных, то эта статья будет тебе интересна.

НЕМНОГО О BZIP2

Я очень сомневаюсь, что в наши дни найдется хоть кто-нибудь, кто не был бы знаком с этим "архиватором". Я более чем уверен, что если тебе когда-либо приходилось скачивать новое ядро linux'а или патч к нему, ты непременно брал .tar.bz2 =) bzip2
- абсолютный лидер по степени lossless-сжатия данных среди всех известных мне GNU'шных средств. Безусловной прелестью bzip2 является наличие очень компактной и удобной thread-safe-библиотеки (библиотека не использует внешних областей памяти, стало быть, её можно безопасно использовать в многопоточных приложениях), предоставляющей пару десятков функция для сжатия блоков данных и для работы с файлами .bz2-формата. 

К объективным недостаткам можно отнести огромную ресурсоёмкость: работа механизмов libbzip2 изрядно медленнее zlib'ных (gzip). Поэтому, если ты планируешь обрабатывать большие объёмы данных и вопрос ресурсоёмкости для тебя критичен (например, если ты хочешь снизить избыточность обмена информацией по относительно скоростным магистралям), обрати своё внимание на
zlib, которая, кстати, имеет порты и интерфейсы практически подо все мыслимые современных платформы и средства разработки. Есть интерфейс даже для Delphi и Visual Basic! =) Если тебе требуется ещё бОльшая скорость (в ущерб, разумеется, эффективности сжатия), то изучи
LZO. Возможно, в некотором будущем я сделаю howto и к этим библиотекам тоже. Если тебе это интересно, сообщи мне об этом по email'у.

РЕКВИЗИТЫ LIBBZIP2

Официальная страница libbzip2 находится на http://sources.redhat.com/bzip2/, отсюда ты сможешь скачать последнюю версию этой библиотеки и документацию к ней. Я
рассматриваю версию 1.0.2, но всё из того что я расскажу верно также и для более ранних версий этой библиотеки. Здесь ты также найдешь список доступных портов этой библиотеки под различные платформы. Я изучал libbzip2 на платформах linux (p3/533) и cygwin под Windows2000 (p4/2200). libbzip2 и скрипты к ней (bzip2, bunzip2, bzcat, etc...) идут в стандартных дистрибутивах linux'а и cygwin'а, так что тебе её даже устанавливать не придётся =) Проверь, есть ли в твоей /usr/include файл bzlib.h и содержит ли твой /usr/lib экспортные и динамические библиотеки libbz2*.

USAGE

file.c:
#include <bzlib.h>
int main (int argc, char **argv, char **envp) {

return 0;
}

Makefile:
gcc file.c -lbz2 -o file.exe

Библиотека libbzip2 экспортирует четыре типа функций:

1) низкоуровневые (low-level interface), с помощью которых программист может предельно глубоко овладеть процессом сжатия/восстановления данных (следует оговориться: настолько предельно глубоко, насколько ему позволено =)));

2) высокоуровневые (high-level interface), предоставляющие возможность работать с файлами .bz2-формата;

3) две специальные очень простые функции (utility functions), одна из который сжимает, а другая -- разжимает блок данных;

4) функции совместимости с zlib (zlib compatibility functons).

Обрати внимание: в libbzip2, все функции и видимые пользователем константы начинаются с префикса BZ2_.

UTILITY FUNCTIONS

Если ты не собираешься работать с файлами в .bz2-формате и добиваться глубокого контроля над процессами сжатия и восстановления инфы, то ты вполне сможешь обойтись двумя очень простыми функциями, BZ2_bzBuffToBuffCompress() и BZ2_bzBuffToBuffDecompress(). Рассмотрим каждую из них в отдельности:

int BZ2_bzBuffToBuffCompress( char *dest,
unsigned int *destLen,
char *source,
unsigned int sourceLen,
int blockSize100k,
int verbosity,
int workFactor );

Эта функция сжимает sourceLen байт из source в dest, размер выделенной памяти под который содержится в destLen. После возврата управления, функция изменяет destLen, помещая туда размер сжатых данных, поэтому destLen передаётся в функцию по указателю. blockSize100k может принимать значение от 1 до 9 и является косвенным указателем на возможный размер памяти, которую функция затребует от системы для проведения операции сжатия. 1 соответствует 1200k, а 9
- 7600k. verbosity может принимать значения от 0 до 4 и соответствует количеству отладочной информации, которая будет выводиться в stdout в процессе работы функции. Устанавливая эту переменную, ты сможешь изучать процесс работы libbzip2. workFactor
- это один из основных параметров работы механизма сжатия программы, который косвенно влияет на скорость работы функции (он не влияет на результат), дефолтное значение
- 30. Если ты хочешь глубже понять эти механизмы, поиграйся с workFactor'ом, установив verbosity в значение 4.

int BZ2_bzBuffToBuffDecompress( char *dest,
unsigned int *destLen,
char *source,
unsigned int sourceLen,
int small,
int verbosity );

Эта функция выполняет обратные первой функции действия. В ней отсутствуют параметры blockSize100k и workFactor (первый явно указан в дескрипторе сжатого куска, а второй необходим лишь при сжатии). Установив параметр small в единичное значение, ты снизишь количество памяти, необходимое для восстановления сжатого куска (примерно в полтора раза), но увеличишь необходимое для проведения этой операции время.

Вот пример использования двух этих функций:

#include <stdio.h>
#include <bzlib.h>
int main (int argc, char **argv, char **envp) {
char *dst;
unsigned int destLen;
char *src;
unsigned int srcLen;
int bsize = 9;
int verbosity = 4;
int factor = 30;
int i;
int rc;

src = (char *)malloc(256*1024);
dst = (char *)malloc(64*1024);
destLen = 65536;

for(i=0;i<256*1024;i++) src[i] = rand();

rc = BZ2_bzBuffToBuffCompress(dst,&destLen,src,256*1024*10,bsize,verbosity,factor);

printf("Return code: %u\n",rc);
printf("Compressed length: %u\n", destLen);

rc = BZ2_bzBuffToBuffDecompress(src,&srcLen,dst,destLen,0,verbosity);

printf("\nReturn code:%u\n",rc);
printf("Uncompressed length: %u\n", srcLen);

return 0;
}

ZLIB COMPATIBILITY FUNCTIONS

Функции совместимости с zlib (BZ2_bzopen, BZ2_bzread, BZ2_bzwrite, BZ2_bzflush, BZ2_bzclose, BZ2_bzerror, BZ2_bzlibVersion) официально не являются частью libbzip2, но они включены в библиотеку и, я думаю, они будут очень многим полезны и интересны. Эти функции работают с .bz2-файлами. Обрати внимание, эти функции работают со специальным типом typedef void BZFILE.

const char *BZ2_bzlibVersion(void) возвращает строку с версией библиотеки.

BZFILE * BZ2_bzopen (const char *path, const char *mode);
BZFILE * BZ2_bzdopen (int fd, const char *mode);

открывают файл (вторая - файловый дескриптор) в указанном в *mode режиме, аналогично fopen и fdopen из stdio.

int BZ2_bzread (BZFILE *b, void *buf, int len);
int BZ2_bzwrite (BZFILE *b, void *buf, int len);

читают и записывают в файл *b len байт из *buf, аналогично fread и fwrite из stdio.

int BZ2_bzflush (BZFILE *b);
void BZ2_bzclose (BZFILE *b);

работают аналогично fflush и fclose из stdio.

const char * BZ2_bzerror (BZFILE *b, int *errnum);

возвращает состояние .bz2-файла *b и кладёт в errnum код ошибки последней проведённой операции.

Учти, что операции записи и сброса буферов в .bz2-файлы не обязательно будут выполнены физически сразу же после их вызова. Логику работы этих операций ты сможешь прочувствовать на этом примере использования zlib compatible functions:

#include <stdio.h>
#include <bzlib.h>

#define DDD "this is a string to put!\n"

int main (int argc, char **argv, char **envp) {

BZFILE *file;
int i;

printf("%s\n",BZ2_bzlibVersion());
printf("Creating bzip2 file...");

file = BZ2_bzopen("./bzfile.bz2","w");
if(!file) {
printf("failed!\n");
return 1;
}
printf("done!\n");

printf("bzwriting...");
fflush(stdout);
for(i=0;i<256*16;i++) {
BZ2_bzwrite(file,DDD,strlen(DDD));
}
printf("done!\n");

printf("bzclosing...");
fflush(stdout);
BZ2_bzclose(file);
printf("done!\n");

return 0;
}

HIGH LEVEL INTERFACE

Функции BZ2_bzReadOpen, BZ2_bzRead, BZ2_bzReadGetUnused, BZ2_bzReadClose, BZ2_bzWriteOpen, BZ2_bzWrite и BZ2_bzWriteClose составляют высокоуровневый интерфейс libbzip2, и, как и zlib compatible functions, позволяют манипулировать .bz2-файлами. Собственно говоря, zlib compatible functions
- это надстройка над верхнеуровневым интерфейсом libbzip2.

Все функции принимают в качестве первого параметра аргумент int *bzerror. После возврата управления каждой функции необходимо прежде всего проверять значение этого аргумента, и лишь затем следует проверять код возврата самой функции.

Если bzerror содержит код ошибки (что угодно, кроме BZ_OK или BZ_STREAM_END), следует немедленно вызвать BZ2_bzReadClose (или BZ2_bzWriteClose, в зависимости от того, чем занимается твоя программа) и освободить все связанные с обрабатываемыми данными ресурсы, так как поведение других функций после возврата ошибки не определено. bzerror должен проверяться после каждого вызова функций high level interface.

Файлы типа FILE *, идущие параметром к функциям BZ2_bzReadOpen и BZ2_bzWriteOpen, должны быть установлены в двоичный формат. (По дефолту это уже так и в linux, и в cygwin).

Высокоуровневые функции не предоставляют возможности использования альтернативных функций выделения и освобождения динамической памяти (такая возможность присутствует в низкоуровневых API), libbzip2 использует стандартные
malloc/free.

BZFILE *BZ2_bzReadOpen( int *bzerror,
FILE *f,
int small,
int verbosity,
void *unused,
int nUnused);

Эта функция совершает подготовку к чтению сжатых данных из файла FILE *f. FILE *f должен ссылаться на уже открытый для чтения файл. Если параметр small установлен в единицу, функция попытается использовать меньшее количество памяти (в ущерб скорости). Значение параметра verbosity мы уже рассматривали. Прежде чем читать данные из файла FILE *f, функция будет читать nUnused байт из void *unused. nUnused не должен превышать BZ_MAX_UNUSED. Если эта фича не требуется, оба последних параметра должны быть установлены в ноль.

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии