【问题标题】:Is it possible to read a compressed file without extracting the file in Objective-C?是否可以读取压缩文件而不在 Objective-C 中提取文件?
【发布时间】:2012-02-15 08:07:09
【问题描述】:

我正在构建一个应用程序,它需要读取 zipfile 中的文件而不提取文件。有没有这种功能的库,或者你能给我一些关于如何解决它的想法吗?

【问题讨论】:

  • 如果你可以在不解压的情况下读取压缩文件,那么解压就没有意义了,你不觉得吗?文件将被永久压缩。
  • @EmilioPelaez:将一部分压缩数据提取到内存中会很有用,这是一种可以随后处理的未压缩流。例如,SAX 解析器可以在压缩的 XML 文件上运行,其中的一部分被提取、解析、丢弃或进一步处理。
  • @EmilioPelaez 请先询问我为什么要这样做,然后再发表评论。感谢 Alex Reynolds 澄清它。
  • 您说的是 zip 压缩文件还是 zip 存档中的文件?
  • @EmilioPelaez - 始终压缩只读文件并非不切实际。毕竟,Java JAR 文件实际上只是一个 zip 文件,类加载器直接从文件中读取成员,而无需创建中间 .class 文件。问题更多在于读写文件 - 写入 zip 文件效率非常低。

标签: iphone objective-c ipad zip gzip


【解决方案1】:

您可以一次解压缩一个充满缓冲区的数据,然后通读该文件,假设该文件是文本并且以您可以增量解析它的方式构造(例如,使用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;
}

【讨论】:

  • 谢谢先生,非常感谢您的帮助。我会看看你的代码并研究它。
  • 我认为他谈到了 zip 存档,因此,即使您的代码会有所帮助,有趣的部分是在存档中找到流的开头(并使用正确的算法解压缩它 -存储,充气等)
  • 不清楚 OP 是指“zip”文件还是简单的压缩文件,但除了解压缩的 zlib 包之外,还有可以“破解”zip 文件格式的开源 API zip 文件成员的默认压缩。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-28
  • 2017-10-08
  • 2016-09-30
  • 2013-11-16
相关资源
最近更新 更多