我使用 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但我不认为它是合理的选择。
答案 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;大小要挑选。这是您应该做出的选择,以便您的应用程序的速度和所需的内存是您所需要的。