tags:

views:

457

answers:

4

Hello,

I have some gzipped files that I want to read in C via fopen and fscanf. Is there anyway to do this without having to gunzip the files to temporary files?

Thanks.

+4  A: 

You can use libzlib to open the gzipped files directly.

It also offers a "gzopen" function that behaves similar to fopen but operates on gzipped files. However, fscanf would probably not work on such a handle, since it expects normal FILE pointers.

Storm
You can use the `fdopen` function to open a file descripto as a `FILE` pointer.
Nathan Fellman
You have to use gzread on files opened with gzopen - C doesn't provide enough polymorphism for libraries to define "custom" file descriptors or `FILE*` handles that work with the POSIX or standard I/O functions. But I don't think there is a gzscanf, so you'll have to read into a buffer and use sscanf.
Steve Jessop
A: 

You can use zlib, but it will require you to replace your I/O calls to be zlib-specific.

unwind
You also need the minizip libraray. The compression in zip is the same but you need the virtual directory handling.
Martin Beckett
A: 

you have to open a pipe to do this. The basic flow in pseudo code is:

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
}

You can use the man pages in the comments for more details on how to do this.

Nathan Fellman
+2  A: 

If popen is fair game, you can do it with fopen and 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;
}

For example:

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