Libzip - 从zip读取文件内容

时间:2012-02-04 10:32:44

标签: c++ c zip zipfile

我使用 libzip 来处理zip文件,一切顺利,直到我需要从zip文件中读取文件 我只需要读取整个文本文件,因此实现PHP“file_get_contents”功能会很棒。
要从zip读取文件,有一个函数
“int zip_fread(struct zip_file * file,void * buf,zip_uint64_t nbytes)“
主要问题我不知道 buf 的大小必须是多少 nbytes 我必须阅读(我需要阅读整个文件,但文件大小不同) 。我可以做一个大的缓冲区来适应它们并读取它的大小,或者做一个while循环直到fread返回-1但我不认为它是合理的选择。

4 个答案:

答案 0 :(得分:4)

您可以尝试使用zip_stat来获取文件大小。 http://linux.die.net/man/3/zip_stat

答案 1 :(得分:3)

我没有使用libzip接口,但是从你编写的内容看起来看起来与文件接口非常相似:一旦你得到了流的句柄,你就一直调用zip_fread(),直到这个函数返回错误( ir,可能,小于请求的字节)。您传递给我们的缓冲区只是一个合理大小的临时缓冲区,用于传输数据。

就个人而言,我可能会为此创建一个流缓冲区,因此一旦设置了zip存档中的文件,就可以使用传统的I / O流方法读取它。这看起来像这样:

struct zipbuf: std::streambuf {
    zipbuf(???): file_(???) {}
private:
    zip_file* file_;
    enum { s_size = 8196 };
    char buffer_[s_size];
    int underflow() {
        int rc(zip_fread(this->file_, this->buffer_, s_size));
        this->setg(this->buffer_, this->buffer_,
                        this->buffer_ + std::max(0, rc));
        return this->gptr() == this->egptr()
            ? traits_type::eof()
            : traits_type::to_int_type(*this->gptr());
    }
};

使用此流缓冲区,您应该能够创建std::istream并将文件读入您​​需要的任何结构:

zipbuf buf(???);
std::istream in(&buf);
...

显然,此代码未经过测试或编译。但是,当您用打开zip文件所需的任何内容替换???时,我认为这应该非常有效。

答案 2 :(得分:2)

这是我编写的一个例程,它从zip流中提取数据并一次打印出一行。这使用zlib,而不是libzip,但如果此代码对您有用,请随时使用它:

#
# 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;
}

答案 3 :(得分:1)

对于任何流媒体,您应该考虑应用的内存要求。 良好的缓冲区大小很大,但根据RAM使用要求,您不希望使用太多内存。较小的缓冲区大小需要您多次调用读写操作,这在时间性能方面是昂贵的。所以,你需要在这两个极端的中间找到一个缓冲区。

通常我使用4096(4KB)的大小,这个大小足以用于许多目的。如果你愿意,你可以变得更大。但是在最坏的情况下,1字节的大小,你将等待很长时间才能完成阅读。

所以回答你的问题,没有&#34;对&#34;大小要挑选。这是您应该做出的选择,以便您的应用程序的速度和所需的内存是您所需要的。