Comment puis-je extraire toutes les données d'une archive bzip2 avec C?
-
29-09-2019 - |
Question
J'ai un fichier concaténé composé d'un certain nombre d'archives de bzip2
. Je sais aussi la taille des morceaux individuels de bzip2
dans ce fichier.
Je voudrais décompresser un flux bzip2
à partir d'un bloc de données bzip2 individuelles et écrire la sortie standard.
Tout d'abord je utiliser fseek
pour déplacer le curseur de fichier à l'octet archive désiré, puis lisez la -chunk « taille » du fichier dans un appel 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);
Le problème est que lorsque je compare la sortie de l'instruction fprintf
avec sortie de l'exécution bzip2
sur la ligne de commande, je reçois deux réponses différentes.
Plus précisément, je reçois moins de sortie de ce code que de courir bzip2
sur la ligne de commande.
Plus précisément, ma sortie de ce code est un plus petit sous-ensemble de la sortie du processus de ligne de commande, et je manque ce qui est dans la fin de la queue du morceau bzip2 d'intérêt.
Je l'ai vérifié par une autre technique que la bzip2
commande en ligne fournit la bonne réponse, et, par conséquent, un problème avec mon code C provoque la sortie à la fin du morceau à disparaître. Je ne sais pas ce qu'est ce problème.
Si vous connaissez bzip2
ou libbzip2
, pouvez-vous donner des conseils sur ce que je fais mal dans l'exemple de code ci-dessus? Je vous remercie de vos conseils.
La solution
Ceci est mon code source:
#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;
}
- Je pris en charge beaucoup sur la vérification des erreurs appropriée. Par exemple, je me suis assuré que
bzError
étaitBZ_OK
ouBZ_STREAM_END
avant d'essayer d'accéder à la mémoire tampon. La documentation indique clairement que pour d'autres valeurs debzError
le nombre de retour est non défini . - Il ne devrait pas vous faire peur que environ 50 pour cent du code sont concernés par la gestion des erreurs. Voilà comment il devrait être. Attendez-vous à des erreurs partout.
- Le code a encore quelques bugs. En cas d'erreurs, il ne libère pas les ressources (
f
,bzf
) correctement.
Et ce sont les commandes que j'utilisé pour le test:
$ 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