Pregunta

Tengo algunos archivos comprimidos que quiero leer en C a través de fopen y fscanf. ¿Hay alguna forma de hacer esto sin tener que comprimir los archivos a archivos temporales?

Gracias.

¿Fue útil?

Solución

Puede usar libzlib para abrir los archivos comprimidos directamente.

También ofrece un "gzopen" función que se comporta de manera similar a fopen pero opera en archivos comprimidos. Sin embargo, fscanf probablemente no funcionaría en un controlador de este tipo, ya que espera punteros de ARCHIVO normales.

Otros consejos

Si popen es un juego justo , puede hacerlo con fopen y 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;
}

Por ejemplo:

$ 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.]

No usar

sprintf(cmd, "zcat %s", argv[1]);
popen(cmd,"r");

para abrir archivos .gz. En su lugar, escapa de argv [1] correctamente. De lo contrario, puede terminar con una vulnerabilidad, especialmente cuando algunos inyectan un argumento argv [1] como

123;rm -rf /

Ya ayuda cambiar las instrucciones anteriores a

sprintf(cmd, "zcat \'%s\'",argv[1]);

También es posible que desee escapar de caracteres como '\ 0', '\' ',' \; ' etc.

Intento de novato en 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;
}

Puede usar zlib , pero requerirá que reemplace sus llamadas de E / S para ser zlib -específico.

tienes que abrir una tubería para hacer esto. El flujo básico en pseudocódigo es:

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
}

Puede usar las páginas man en los comentarios para obtener más detalles sobre cómo hacerlo.

Puede usar zlib y ajustarlo a un puntero de archivo normal, de esta manera puede usar fscanf, fread, etc. transparentemente.

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 bastante simple usar zlib para abrir archivos .gz . Hay un manual razonable en zlib.net .

Aquí hay un ejemplo rápido para comenzar:

#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;
}

Recuerde vincular con zlib , en UNIX gcc ... -lz

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top