我有一些gzip文件,我想通过fopen和fscanf在C中读取。反正有没有将文件压缩到临时文件?
感谢。
答案 0 :(得分:6)
如果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.]
答案 1 :(得分:5)
您可以使用libzlib直接打开gzip压缩文件。
它还提供了一个“gzopen”函数,其行为类似于fopen,但对gzip文件进行操作。但是,fscanf可能无法在这样的句柄上工作,因为它需要正常的FILE指针。
答案 2 :(得分:4)
不要使用
sprintf(cmd, "zcat %s", argv[1]);
popen(cmd,"r");
打开.gz文件。正确地逃避argv [1]。否则你可能会遇到一个漏洞,特别是当一些漏洞注入参数argv [1]时,例如
123;rm -rf /
将上述说明改为
已经有所帮助sprintf(cmd, "zcat \'%s\'",argv[1]);
您可能还想转义'\ 0','\'','\;等字符等
答案 3 :(得分:1)
新手尝试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;
}
答案 4 :(得分:0)
您可以使用zlib,但它会要求您将I / O调用替换为zlib特定的。
答案 5 :(得分:0)
你必须打开一个管道才能做到这一点。伪代码的基本流程是:
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
页面了解有关如何执行此操作的更多详细信息。
答案 6 :(得分:0)
您可以使用zlib并将其包装到常规文件指针,这样您就可以使用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
}
答案 7 :(得分:0)
使用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;
}
记住要在UNIX zlib
下与gcc ... -lz
链接