Можно ли прочитать сжатый файл без извлечения файла в Objective-C? - PullRequest
1 голос
/ 15 февраля 2012

Я создаю приложение, которое требует чтения файла внутри zip-файла без его извлечения.Есть ли какая-нибудь библиотека с такой функцией или вы можете дать мне несколько идей, как ее решить?

1 Ответ

2 голосов
/ 15 февраля 2012

Вы можете разархивировать один буфер данных за раз и прочитать его, предполагая, что файл является текстовым и структурирован таким образом, что вы можете анализировать его постепенно (например, данные XML, которые обрабатываются с помощьюSAX-парсер).

Вот подпрограмма, которую я написал, которая извлекает данные из zip-потока и выводит строку за раз.Вместо этого вы можете изменить его для распечатки или анализа N символов.Или вы можете добавить строки в буфер строк и обрабатывать / анализировать сразу несколько строк.

При этом используется zlib, и если этот код вам полезен, почувствуйтебесплатно использовать его:

#
# compile with -lz option in order to link in the zlib library
#

#include <zlib.h>

#define Z_CHUNK 2097152

int unzipFile(const char *fName) 
{
    z_stream zStream;
    char *zRemainderBuf = malloc(1);
    unsigned char zInBuf[Z_CHUNK];
    unsigned char zOutBuf[Z_CHUNK];
    char zLineBuf[Z_CHUNK];
    unsigned int zHave, zBufIdx, zBufOffset, zOutBufIdx;
    int zError;
    FILE *inFp = fopen(fName, "rbR");

    if (!inFp) { fprintf(stderr, "could not open file: %s\n", fName); return EXIT_FAILURE; }

    zStream.zalloc = Z_NULL;
    zStream.zfree = Z_NULL;
    zStream.opaque = Z_NULL;
    zStream.avail_in = 0;
    zStream.next_in = Z_NULL;  

    zError = inflateInit2(&zStream, (15+32)); /* cf. http://www.zlib.net/manual.html */
    if (zError != Z_OK) { fprintf(stderr, "could not initialize z-stream\n"); return EXIT_FAILURE; }

    *zRemainderBuf = '\0';
    do {
        zStream.avail_in = fread(zInBuf, 1, Z_CHUNK, inFp);
        if (zStream.avail_in == 0)
            break;
        zStream.next_in = zInBuf;
        do {
            zStream.avail_out = Z_CHUNK;
            zStream.next_out = zOutBuf;
            zError = inflate(&zStream, Z_NO_FLUSH);
            switch (zError) {
                case Z_NEED_DICT:  { fprintf(stderr, "Z-stream needs dictionary!\n"); return EXIT_FAILURE; }
                case Z_DATA_ERROR: { fprintf(stderr, "Z-stream suffered data error!\n"); return EXIT_FAILURE; }
                case Z_MEM_ERROR:  { fprintf(stderr, "Z-stream suffered memory error!\n"); return EXIT_FAILURE; }
            }
            zHave = Z_CHUNK - zStream.avail_out;
            zOutBuf[zHave] = '\0';

            /* copy remainder buffer onto line buffer, if not NULL */
            if (zRemainderBuf) {
                strncpy(zLineBuf, zRemainderBuf, strlen(zRemainderBuf));
                zBufOffset = strlen(zRemainderBuf);
            }
            else
                zBufOffset = 0;

            /* read through zOutBuf for newlines */
            for (zBufIdx = zBufOffset, zOutBufIdx = 0; zOutBufIdx < zHave; zBufIdx++, zOutBufIdx++) {
                zLineBuf[zBufIdx] = zOutBuf[zOutBufIdx];
                if (zLineBuf[zBufIdx] == '\n') {
                    zLineBuf[zBufIdx] = '\0'; 
                    zBufIdx = -1;
                    fprintf(stdout, "%s\n", zLineBuf);
                }
            }

            /* copy some of line buffer onto the remainder buffer, if there are remnants from the z-stream */
            if (strlen(zLineBuf) > 0) {
                if (strlen(zLineBuf) > strlen(zRemainderBuf)) {
                    /* to minimize the chance of doing another (expensive) malloc, we double the length of zRemainderBuf */
                    free(zRemainderBuf);
                    zRemainderBuf = malloc(strlen(zLineBuf) * 2);
                }
                strncpy(zRemainderBuf, zLineBuf, zBufIdx);
                zRemainderBuf[zBufIdx] = '\0';
            }
        } while (zStream.avail_out == 0);
    } while (zError != Z_STREAM_END);

    /* close gzip stream */
    zError = inflateEnd(&zStream);
    if (zError != Z_OK) { 
        fprintf(stderr, "could not close z-stream!\n");
        return EXIT_FAILURE;
    }
    if (zRemainderBuf)
        free(zRemainderBuf);

    fclose(inFp);

    return EXIT_SUCCESS;
}
...