Pergunta

Eu tenho alguns arquivos gzipped que eu quero ler em C via fopen e fscanf. Existe uma maneira de fazer isso sem ter que gunzip os arquivos para arquivos temporários?

Graças.

Foi útil?

Solução

Você pode usar libzlib para abrir os arquivos gzipped diretamente.

Ele também oferece uma função "gzopen" que se comporta semelhante a fopen, mas funciona em arquivos gzipped. No entanto, fscanf provavelmente não trabalho em tais pega um, uma vez que espera ponteiros de arquivo normal.

Outras dicas

Se popen é um jogo justo, você pode fazê-lo com fopen e 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 exemplo:

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

Não use

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

para arquivos .gz abertos. Corretamente escapar argv [1] em vez. De contrário pode acabar com uma vulnerabilidade, especialmente quando alguns injeta um argv argumento [1] como

123;rm -rf /

Ele já ajuda a mudar as instruções acima em

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

Você também pode querer escapar caracteres como '\ 0', '\'', '\'; etc.

Novato tentativa de 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;
}

Você pode usar zlib , mas vai exigir que você substitua as chamadas de I / O para ser zlib espec�ico.

você tem que abrir um canal para fazer isso. O fluxo básico em pseudo-código é:

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
}

Você pode usar as páginas man nos comentários para mais detalhes sobre como fazer isso.

Você pode usar zlib e envolvê-la para um ponteiro de arquivo regular, desta forma você pode usar fscanf, fread, etc. transparente.

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
}

É muito simples de usar zlib a arquivos .gz abertos. Há um longo manual do razoável em zlib.net .

Aqui está um exemplo rápido para você começar:

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

Lembre-se de ligação com zlib, sob UNIX gcc ... -lz

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top