【问题标题】:Libzip - read file contents from zipLibzip - 从 zip 读取文件内容
【发布时间】:2012-02-26 18:03:17
【问题描述】:

我使用 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,但我认为这不是合理的选择。

【问题讨论】:

    标签: c++ c zip zipfile


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      我没有使用过 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 文件所需的任何内容时,我认为这应该很有效。

      【讨论】:

        【解决方案3】:

        这是我编写的一个例程,它从压缩流中提取数据并一次打印出一行。这里使用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;
        }
        

        【讨论】:

          【解决方案4】:

          对于任何流式传输,您都应该考虑应用的内存要求。 一个好的缓冲区大小很大,但您不希望使用太多内存,具体取决于您的 RAM 使用要求。较小的缓冲区大小将需要您多次调用读写操作,这在时间性能方面是昂贵的。因此,您需要在这两个极端之间找到一个缓冲区。

          通常我使用 4096 (4KB) 的大小,这对于许多用途来说已经足够大了。如果你愿意,你可以做得更大。但在最坏的情况下,大小为 1 字节,您将等待很长时间才能完成读取。

          所以要回答您的问题,没有“正确”的尺寸可供选择。这是您应该做出的选择,这样您的应用程序的速度和它所需的内存就是您所需要的。

          【讨论】:

            猜你喜欢
            • 2013-03-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多