2

質問は奇妙に思えるかもしれませんが、スペルを間違えたわけではありません。ダウンロードしたデータをHDDに書き込まずに解凍したいのです。そのために、動的に割り当てられたバッファーにダウンロードし、使用するzlibラッパー(miniunzip)に送信します。問題は、この実装が非常に長く(2〜3K行)、数行だけ書き直す必要がないようにすることです。FILE *構造を介してバッファを読み取る方法があるかどうかを知りたいです(miniunzipは独自の構造を使用しますが、ローダーの下に「fopen()」が隠れているのを見つけました)。それが助けになるなら、私はその長さを知っています。

事前に感謝し、文法が貧弱で失礼します。

私はWindowsとUNIXシステム(OSX / GNU Linux)の両方で作業しています。

4

2 に答える 2

4

zlibに含まれているminizipライブラリについて話している場合は、使用するunzOpen2I/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);
}
于 2012-12-19T23:43:42.713 に答える
1

質問を要約すると、FILE*メモリ内バッファのインターフェイスを提供する必要があります。いいえ、それはできません。などのfread()呼び出しは、実際には、持っていない開いているファイル記述子を処理するシステム呼び出しを行うことになります。

あなたはこれを複雑にしすぎています。解凍コードは、ほとんどの場合、メモリ内にあるバッファから機能します。それらがファイルインターフェイスを持っている場合、それは確かにファイルをメモリに読み込んでから解凍する(おそらくメモリを節約するためにチャンクで)処理する単なるラッパーです。与えたバッファー(ポインターと長さのみ)を解凍するための呼び出しを含む解凍ライブラリーを見つけることができるはずです。

ダウンロードしたデータをハードドライブに書き込みたくない理由は確かにあなた次第ですが、これが悪ではなく善のためであることを願っています。


もう1つのオプションは、ダウンロード中に書き込み、解凍中に読み取るメモリマップトファイルを開くことです。ファイルがディスクに書き込まれないように指定する方法があるかもしれませんが、それについてはよくわかりませんまた、これはWindowsとLinuxでは大きく異なります。

これらは役立つかもしれません:

于 2012-12-19T21:59:59.277 に答える