Как извлечь все данные из архива bzip2 с помощью C?
У меня есть объединенный файл, состоящий из некоторого числа bzip2
архивы. Я также знаю размеры человека bzip2
куски в этом файле.
Я хотел бы распаковать bzip2
поток от отдельного блока данных bzip2, и записать вывод в стандартный вывод.
Сначала я использую fseek
для перемещения курсора файла к нужному байту архива, а затем считайте "размерный" фрагмент файла в BZ2_bzRead
вызов:
int headerSize = 1234;
int firstChunkSize = 123456;
FILE *fp = fopen("pathToConcatenatedFile", "r+b");
char *bzBuf = malloc(sizeof(char) * firstChunkSize);
int bzError, bzNBuf;
BZFILE *bzFp = BZ2_bzReadOpen(&bzError, *fp, 0, 0, NULL, 0);
# move cursor past header of known size, to the first bzip2 "chunk"
fseek(*fp, headerSize, SEEK_SET);
while (bzError != BZ_STREAM_END) {
# read the first chunk of known size, decompress it
bzNBuf = BZ2_bzRead(&bzError, bzFp, bzBuf, firstChunkSize);
fprintf(stdout, bzBuf);
}
BZ2_bzReadClose(&bzError, bzFp);
free(bzBuf);
fclose(fp);
Проблема в том, что когда я сравниваю вывод fprintf
заявление с выходом из бега bzip2
в командной строке я получаю два разных ответа.
В частности, я получаю меньше вывода из этого кода, чем при запуске bzip2
в командной строке.
Более конкретно, мой вывод из этого кода является меньшим подмножеством вывода из процесса командной строки, и мне не хватает того, что находится в хвостовой части интересующего блока bzip2.
Я проверил с помощью другой техники, что командная строка bzip2
обеспечивает правильный ответ, и, следовательно, некоторая проблема с моим кодом C приводит к тому, что вывод в конце фрагмента пропадает. Я просто не знаю, что это за проблема.
Если вы знакомы с bzip2
или же libbzip2
Можете ли вы дать совет о том, что я делаю неправильно в приведенном выше примере кода? Спасибо за совет.
1 ответ
Это мой исходный код:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <bzlib.h>
int
bunzip_one(FILE *f) {
int bzError;
BZFILE *bzf;
char buf[4096];
bzf = BZ2_bzReadOpen(&bzError, f, 0, 0, NULL, 0);
if (bzError != BZ_OK) {
fprintf(stderr, "E: BZ2_bzReadOpen: %d\n", bzError);
return -1;
}
while (bzError == BZ_OK) {
int nread = BZ2_bzRead(&bzError, bzf, buf, sizeof buf);
if (bzError == BZ_OK || bzError == BZ_STREAM_END) {
size_t nwritten = fwrite(buf, 1, nread, stdout);
if (nwritten != (size_t) nread) {
fprintf(stderr, "E: short write\n");
return -1;
}
}
}
if (bzError != BZ_STREAM_END) {
fprintf(stderr, "E: bzip error after read: %d\n", bzError);
return -1;
}
BZ2_bzReadClose(&bzError, bzf);
return 0;
}
int
bunzip_many(const char *fname) {
FILE *f;
f = fopen(fname, "rb");
if (f == NULL) {
perror(fname);
return -1;
}
fseek(f, 0, SEEK_SET);
if (bunzip_one(f) == -1)
return -1;
fseek(f, 42, SEEK_SET); /* hello.bz2 is 42 bytes long in my case */
if (bunzip_one(f) == -1)
return -1;
fclose(f);
return 0;
}
int
main(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr, "usage: bunz <fname>\n");
return EXIT_FAILURE;
}
return bunzip_many(argv[1]) != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
- Я очень заботился о правильной проверке ошибок. Например, я убедился, что
bzError
былоBZ_OK
или жеBZ_STREAM_END
прежде чем пытаться получить доступ к буферу. В документации четко сказано, что для других значенийbzError
возвращенное число не определено. - Вас не должно пугать, что около 50 процентов кода связаны с обработкой ошибок. Так и должно быть. Ожидайте ошибки везде.
- В коде все еще есть ошибки. В случае ошибок не освобождает ресурсы (
f
,bzf
) должным образом.
И эти команды я использовал для тестирования:
$ echo hello > hello
$ echo world > world
$ bzip2 hello
$ bzip2 world
$ cat hello.bz2 world.bz2 > helloworld.bz2
$ gcc -W -Wall -Os -o bunz bunz.c -lbz2
$ ls -l *.bz2
-rw-r--r-- 1 roland None 42 Oct 12 09:26 hello.bz2
-rw-r--r-- 1 roland None 86 Oct 12 09:36 helloworld.bz2
-rw-r--r-- 1 roland None 44 Oct 12 09:26 world.bz2
$ ./bunz.exe helloworld.bz2
hello
world