فتح الملفات المضغوطة بطريقة gzip للقراءة في C دون خلق الملفات المؤقتة
سؤال
ولدي بعض الملفات المضغوطة بطريقة 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