这个问题可能看起来很奇怪,但我并没有拼写错误: 我想解压缩下载的一些数据,而不是将它们写在硬盘上。为此,我在动态分配的缓冲区中下载它,我想将它发送到我使用的zlib包装器(miniunzip)。问题是这个实现很长(2-3K行),我想避免只为几行重写它。 我想知道是否有任何方法可以通过FILE *结构读取缓冲区(miniunzip使用它自己的结构,但我在加载器下发现了一个“fopen()”hiden)。我知道它的长度,如果它可以帮助。
提前致谢,请原谅我糟糕的语法。
我正在使用Windows和UNIX系统(OSX / GNU Linux)。
答案 0 :(得分:2)
如果您正在讨论zlib附带的minizip库,您可以使用unzOpen2
函数,该函数允许您指定包含要使用的I / O函数的结构。这应该让你开始:
struct zmem_data {
char *buf;
size_t length;
};
static voidpf zmemopen(voidpf opaque, const char *filename, int mode) {
if ((mode&ZLIB_FILEFUNC_MODE_READWRITEFILTER) != ZLIB_FILEFUNC_MODE_READ) return NULL;
uLong *pos = malloc(sizeof(uLong));
*pos = 0;
return pos;
}
static uLong zmemread(voidpf opaque, voidpf stream, void* buf, uLong size) {
struct zmem_data *data = (struct zmem_data*)opaque;
uLong *pos = (uLong*)stream;
uLong remaining = data->length - *pos;
uLong readlength = size < remaining ? size : remaining;
if (*pos > data->length) return 0;
memcpy(buf, data->buf+*pos, readlength);
*pos += readlength;
return readlength;
}
static uLong zmemwrite(voidpf opaque, voidpf stream, const void *buf, uLong size) {
/* no write support for now */
return 0;
}
static int zmemclose(voidpf opaque, voidpf stream) {
free(stream);
return 0;
}
static int zmemerror(voidpf opaque, voidpf stream) {
if (stream == NULL) return 1;
else return 0;
}
static long zmemtell(voidpf opaque, voidpf stream) {
return *(uLong*)stream;
}
static long zmemseek(voidpf opaque, voidpf stream, uLong offset, int origin) {
struct zmem_data *data = (struct zmem_data*)opaque;
uLong *pos = (uLong*)stream;
switch (origin) {
case ZLIB_FILEFUNC_SEEK_SET:
*pos = offset;
break;
case ZLIB_FILEFUNC_SEEK_CUR:
*pos = *pos + offset;
break;
case ZLIB_FILEFUNC_SEEK_END:
*pos = data->length + offset;
break;
default:
return -1;
}
return 0;
}
static void init_zmemfile(zlib_filefunc_def *inst, char *buf, size_t length) {
struct zmem_data *data = malloc(sizeof(struct zmem_data));
data->buf = buf;
data->length = length;
inst->opaque = data;
inst->zopen_file = zmemopen;
inst->zread_file = zmemread;
inst->zwrite_file = zmemwrite;
inst->ztell_file = zmemtell;
inst->zseek_file = zmemseek;
inst->zclose_file = zmemclose;
inst->zerror_file = zmemerror;
}
static void destroy_zmemfile(zlib_filefunc_def *inst) {
free(inst->opaque);
inst->opaque = NULL;
}
void example() {
zlib_filefunc_dec fileops;
init_zmemfile(&fileops, buffer, buffer_length);
unzFile zf = unzOpen2(NULL, &fileops);
/* ... process zip file ... */
unzClose(zf);
destroy_zmemfile(&fileops);
}
答案 1 :(得分:1)
总结您的问题:您希望为内存缓冲区提供FILE*
接口。不,你做不到。 fread()
等调用实际上最终会进行处理您没有的打开文件描述符的系统调用。
你过于复杂了。解压缩代码几乎总是来自内存中的缓冲区。如果他们有一个文件接口,当然这只是一个包装器,它处理将文件读入内存然后解压缩(可能以块为单位来节省内存)。你应该能够找到一个解压缩库,调用解压缩你给它的缓冲区(只是一个指针和一个长度)。
为什么你不想把下载的数据写入硬盘驱动器当然取决于你,但我希望这是好的,而不是为了邪恶。
另一种选择是打开一个内存映射文件,在下载过程中写入该文件,并在解压缩过程中读取。 可能是一种指定文件不能写入磁盘但我不确定的方法。此外,这在windows和linux之间会有很大不同。
这些可能有所帮助: