فتح الملفات المضغوطة بطريقة gzip للقراءة في C دون خلق الملفات المؤقتة

StackOverflow https://stackoverflow.com/questions/1820144

  •  10-07-2019
  •  | 
  •  

سؤال

ولدي بعض الملفات المضغوطة بطريقة gzip التي أريد أن أقرأ في C عن طريق الدالة fopen وfscanf. هناك على أية حال للقيام بذلك دون الحاجة إلى غونزيب الملفات إلى ملفات مؤقتة؟

وشكرا.

هل كانت مفيدة؟

المحلول

ويمكنك استخدام libzlib لفتح الملفات المضغوطة بطريقة gzip مباشرة.

وكما أنها توفر وظيفة "gzopen" أن يتصرف على غرار الدالة fopen ولكنها تعمل على الملفات المضغوطة بطريقة gzip. ومع ذلك، fscanf ربما لا تعمل على مثل هذا التعامل، لأنها تتوقع مؤشرات FILE العادية.

نصائح أخرى

إذا popen هي لعبة عادلة، يمكنك أن تفعل ذلك مع fopen و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;
}

وعلى سبيل المثال:

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

لا تستخدم

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

ولفتح ملفات .gz. الهروب بشكل صحيح ARGV [1] بدلا من ذلك. قد ينتهي إلا مع الضعف، وخصوصا عندما يقحم بعض حجة ARGV [1] مثل

123;rm -rf /

وكما أنه يساعد بالفعل إلى تغيير التعليمات أعلاه في

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

وأنت قد تحتاج أيضا إلى الهروب الشخصيات مثل '\ 0'، '\' '،' \؛ " وما إلى ذلك.

ومحاولة عضو جديد في 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;
}

ويمكنك استخدام زليب ، ولكنها سوف تتطلب منك استبدال الخاص بك I / O يدعو إلى أن تكون زليب محددة.

وكان لديك لفتح أنبوب للقيام بذلك. تدفق الأساسي في رمز زائف هو:

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
}

ويمكنك استخدام صفحات man في تعليق ل مزيد من التفاصيل حول كيفية القيام بذلك.

ويمكنك استخدام زليب وألفه إلى مؤشر ملف العادية، وبهذه الطريقة يمكنك استخدام fscanf، fread، الخ. بشفافية.

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
}

وانها بسيطة جدا لاستخدام zlib لفتح ملفات .gz. هناك دليل معقول في أكثر من zlib.net .

وهنا مثال سريع للحصول على انك بدأته:

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

وحفظ لربط مع zlib، تحت UNIX gcc ... -lz

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top