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.

War es hilfreich?

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 ändern
sprintf(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

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top