Wie extrahiere ich alle die Daten aus einem bzip2-Archiv mit C?
-
29-09-2019 - |
Frage
Ich habe eine verkettete Datei von einer Anzahl von bzip2
Archiven aus. Ich weiß, dass auch die Größen der einzelnen bzip2
Stücke in dieser Datei.
Ich möchte einen bzip2
Strom von einem einzelnen bzip2 Datenblock dekomprimieren, und die Ausgabe auf die Standardausgabe schreiben.
Zuerst habe ich Gebrauch fseek
die Datei Cursor auf das gewünschte Archiv Byte zu bewegen, und dann lesen Sie die „Größe“ -chunk der Datei in einen BZ2_bzRead
Aufruf:
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);
Das Problem ist, dass, wenn ich die Ausgabe der fprintf
Anweisung mit Ausgang vergleichen von laufenden bzip2
auf der Kommandozeile, bekomme ich zwei verschiedene Antworten.
Insbesondere bekomme ich weniger Ausgabe von diesem Code als von bzip2
auf der Kommandozeile ausgeführt wird.
Insbesondere aus diesem Code meine Ausgabe ist eine kleinere Teilmenge des Ausgangs von der Kommandozeile Prozess, und ich bin fehle, was in dem Schwanzende des bzip2 Brockens von Interesse.
Ich habe durch eine andere Technik Nachweis erbracht, dass die Befehlszeile bzip2
die richtige Antwort liefert, und daher ein Problem mit meinem C-Code ausgegeben wird am Ende des Blockes verursacht abhanden zu kommen. Ich weiß nur nicht, was das Problem ist.
Wenn Sie mit bzip2
oder libbzip2
vertraut sind, können Sie bieten einen Rat, was ich oben falsch in dem Codebeispiel mache? Vielen Dank für Ihre Beratung.
Lösung
Das ist mein Quellcode:
#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;
}
- Ich sorgte mich sehr viel über die richtige Fehlerprüfung. Zum Beispiel habe ich darauf geachtet, dass
bzError
warBZ_OK
oderBZ_STREAM_END
, bevor Sie den Puffer zugreifen. Die Dokumentation sagt deutlich, dass für andere Werte vonbzError
die zurückgegebene Zahl ist undefined . - Es sollte Sie nicht erschrecken, dass etwa 50 Prozent des Codes mit Fehlerbehandlung betroffen sind. Das ist wie es sein sollte. Erwarten Sie Fehler überall.
- Der Code hat noch einige Bugs. Bei Fehlern entbindet sie nicht über die Ressourcen (
f
,bzf
) richtig.
Und das sind die Befehle, die ich für den Test verwendet:
$ 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