Öffnen gzip-Dateien für ohne temporäre Dateien in C Lesen
Frage
Ich habe einige gzip-Dateien, die ich in C über fopen und fscanf lesen möchten. Gibt es trotzdem, dies zu tun, ohne die Dateien in temporären Dateien gunzip?
Danke.
Lösung
Sie können mit libzlib die gzip-Dateien direkt öffnen.
Es bietet auch eine „gzopen“ -Funktion, die fopen ähnlich verhält, sondern arbeitet auf gzip-Dateien. Allerdings würde fscanf wahrscheinlich nicht auf einem solchen Griff arbeiten, da es normal FILE Zeiger erwartet.
Andere Tipps
Wenn popen
ist faires Spiel, können Sie es mit fopen
tun können und fscanf
:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[])
{
const char prefix[] = "zcat ";
const char *arg;
char *cmd;
FILE *in;
char buf[4096];
if (argc != 2) {
fprintf(stderr, "Usage: %s file\n", argv[0]);
return 1;
}
arg = argv[1];
cmd = malloc(sizeof(prefix) + strlen(arg) + 1);
if (!cmd) {
fprintf(stderr, "%s: malloc: %s\n", argv[0], strerror(errno));
return 1;
}
sprintf(cmd, "%s%s", prefix, arg);
in = popen(cmd, "r");
if (!in) {
fprintf(stderr, "%s: popen: %s\n", argv[0], strerror(errno));
return 1;
}
while (fscanf(in, "%s", buf) == 1)
printf("%s: got [%s]\n", argv[0], buf);
if (ferror(in)) {
fprintf(stderr, "%s: fread: %s\n", argv[0], strerror(errno));
return 1;
}
else if (!feof(in)) {
fprintf(stderr, "%s: %s: unconsumed input\n", argv[0], argv[1]);
return 1;
}
return 0;
}
Zum Beispiel:
$ zcat file.gz
Every good boy does fine.
$ ./gzread file.gz
./gzread: got [Every]
./gzread: got [good]
./gzread: got [boy]
./gzread: got [does]
./gzread: got [fine.]
Verwenden Sie keine
sprintf(cmd, "zcat %s", argv[1]);
popen(cmd,"r");
öffnen gz-Dateien. entkommen richtig argv [1] statt. Sie können sonst mit einer Schwachstelle am Ende, vor allem, wenn einige ein Argument injizieren argv [1] wie
123;rm -rf /
Es hilft schon die obige Anweisung in
zu ändernsprintf(cmd, "zcat \'%s\'",argv[1]);
Sie können auch Zeichen wie '\ 0' zu entkommen, '\'‘, '\;' etc.
Newbie Versuch gzscanf ():
#include <stdio.h>
#include <stdarg.h>
#include <zlib.h>
#define MAXLEN 256
int gzscanf(gzFile *stream, const char *fmt, ...) {
/* read one line from stream (up to newline) and parse with sscanf */
va_list args;
va_start(args, fmt);
int n;
static char buf[MAXLEN];
if (NULL == gzgets(stream, buf, MAXLEN)) {
printf("gzscanf: Failed to read line from gz file.\n");
exit(EXIT_FAILURE);
}
n = vsscanf(buf, fmt, args);
va_end(args);
return n;
}
Sie können zlib , aber es erfordert, dass Sie Ihre I ersetzen / O ruft zlib zu sein -spezifische.
Sie müssen ein Rohr öffnen, um dies zu tun. Die Grundströmung in Pseudo-Code ist:
create pipe // man pipe
fork // man fork
if (parent) {
close the writing end of the pipe // man 2 close
read from the pipe // man 2 read
} else if (child) {
close the reading end of the pipe // man 2 close
overwrite the file descriptor for stdout with the writing end of the pipe // man dup2
call exec() with gzip and the relevant parameters // man 3 exec
}
Sie können die man
Seiten in den Kommentaren, um weitere Informationen verwenden, wie dies zu tun.
Sie können die zlib verwenden und es zu einem regulären Dateizeiger wickeln, auf diese Weise Sie fscanf verwenden können, fread, etc. transparent.
FILE *myfopen(const char *path, const char *mode)
{
#ifdef WITH_ZLIB
gzFile *zfp;
/* try gzopen */
zfp = gzopen(path,mode);
if (zfp == NULL)
return fopen(path,mode);
/* open file pointer */
return funopen(zfp,
(int(*)(void*,char*,int))gzread,
(int(*)(void*,const char*,int))gzwrite,
(fpos_t(*)(void*,fpos_t,int))gzseek,
(int(*)(void*))gzclose);
#else
return fopen(path,mode);
#endif
}
Es ist ganz einfach zlib
verwenden .gz
Dateien zu öffnen. Es ist ein vernünftiges Handbuch über zlib.net .
Hier ist ein kleines Beispiel für den Anfang:
#include <stdio.h>
#include <zlib.h>
int main( int argc, char **argv )
{
// we're reading 2 text lines, and a binary blob from the given file
char line1[1024];
char line2[1024];
int blob[64];
if (argc > 1)
{
const char *filename = argv[1];
gzFile gz_in = gzopen( filename, "rb" ); // same as fopen()
if (gz_in != NULL)
{
if ( gzgets( gz_in, line1, sizeof(line1) ) != NULL ) // same as fgets()
{
if ( gzgets( gz_in, line2, sizeof(line2) ) != NULL )
{
if ( gzfread( blob, sizeof(int), 64, gz_in ) == 64 ) // same as fread()
{
printf("Line1: %s", line1);
printf("Line2: %s", line2);
// ...etc
}
}
}
gzclose(gz_in); // same as fclose()
}
else
{
printf( "Failed to GZ-open [%s]\n", filename );
}
}
return 0;
}
Denken Sie daran, mit zlib
zu verbinden, unter UNIX gcc ... -lz