最近遇到需要在cocos中解压zip的需求就了解了下
以下代码摘自: http://www.cocoachina.com/bbs/read.php?tid=212537
// Open the zip file std::string outFileName = filename; unzFile zipfile = unzOpen(outFileName.c_str()); if (!zipfile){ CCLOG("can not open downloaded zip file %s", outFileName.c_str()); return false; } // Get info about the zip file unz_global_info global_info; if (unzGetGlobalInfo(zipfile, &global_info) != UNZ_OK){ CCLOG("can not read file global info of %s", outFileName.c_str()); unzClose(zipfile); return false; } const int BUFFER_SIZE = 8192; const int MAX_FILENAME = 512;
// Buffer to hold data read from the zip file char readBuffer[BUFFER_SIZE]; // Loop to extract all files. uLong i; for (i = 0; i < global_info.number_entry; ++i){ // Get info about current file. unz_file_info fileInfo; char fileName[MAX_FILENAME]; if (unzGetCurrentFileInfo(zipfile, &fileInfo, fileName, MAX_FILENAME, NULL, 0, NULL, 0) != UNZ_OK){ CCLOG("can not read file info"); unzClose(zipfile); return false; } std::string storagePath = destPath; std::string fullPath = storagePath + fileName; // Check if this entry is a directory or a file. const size_t filenameLength = strlen(fileName); if (fileName[filenameLength - 1] == '/'){ // get all dir std::string fileNameStr = std::string(fileName); size_t position = 0; while ((position = fileNameStr.find_first_of("/", position)) != std::string::npos){ std::string dirPath = storagePath + fileNameStr.substr(0, position); // Entry is a direcotry, so create it. // If the directory exists, it will failed scilently. if (!createDirectory(dirPath.c_str())){ CCLOG("can not create directory %s", dirPath.c_str()); //unzClose(zipfile); //return false; } position++; } } else { // Entry is a file, so extract it. // Open current file. if (unzOpenCurrentFile(zipfile) != UNZ_OK) { CCLOG("can not open file %s", fileName); unzClose(zipfile); return false; } // Create a file to store current file. FILE *out = fopen(fullPath.c_str(), "wb"); if (!out) { CCLOG("can not open destination file %s", fullPath.c_str()); unzCloseCurrentFile(zipfile); unzClose(zipfile); return false; } // Write current file content to destinate file. int error = UNZ_OK; do { error = unzReadCurrentFile(zipfile, readBuffer, BUFFER_SIZE); if (error < 0) { CCLOG("can not read zip file %s, error code is %d", fileName, error); unzCloseCurrentFile(zipfile); unzClose(zipfile); return false; } if (error > 0) { fwrite(readBuffer, error, 1, out); } } while (error > 0); fclose(out); } unzCloseCurrentFile(zipfile); // Goto next entry listed in the zip file. if ((i + 1) < global_info.number_entry) { if (unzGoToNextFile(zipfile) != UNZ_OK) { CCLOG("can not read next file"); unzClose(zipfile); return false; } } }
使用zlib 的上层封装 minizip 的接口,但是 在ios上会出现非zip后缀的文件,无法读取的尴尬,主要问题出在unzOpen方法。
看了下 可以使用unzOpenBuffer方法就能避免掉这个问题。就变成了:
std::string outFileName = filename; ssize_t size = 0; unsigned char *zipFileData = FileUtils::getInstance()->getFileData(outFileName, "rb", &size); unzFile zipfile = unzOpenBuffer(zipFileData, size); ......
或者直接用cocos封装好的 ZipFile ,也就是:
ZipFile *zip = nullptr; if (zipFileData) { zip = ZipFile::createWithBuffer(zipFileData, size); }
这样就ok。同时了解了下zip格式:
Offset | Bytes | Contents | Descriptor |
---|---|---|---|
LOCAL FILE HEADER | |||
00000000 | 4 | 50 4B 03 04 | 文件头标识(0x04034b50) |
00000004 | 2 | 0A 00 | 解压文件所需 pkware最低版本 |
00000006 | 2 | 00 00 | 通用比特标志位 |
00000008 | 2 | 08 00 | 压缩方式 |
0000000A | 2 | E1 5D | 文件最后修改时间 |
0000000C | 2 | CC 48 | 文件最后修改日期 |
0000000E | 4 | 61 D3 72 09 | crc-32校验码 |
00000012 | 4 | 08 00 00 00 | 压缩后的大小 |
00000016 | 4 | 06 00 00 00 | 未压缩的大小 |
0000001A | 2 | 07 00 | 文件名长度 |
0000001C | 2 | 00 00 | 扩展区长度 |
0000001E | 6 | 31 32 33 2E 74 78 74 | 文件名 123.txt |
FILE DATA | |||
00000025 | 8 | 33 34 32 36 31 35 03 00 | 压缩文件数据,此处就是压缩文本文件123.txt压缩后的数据 |
Central Directory Header | |||
0000002D | 4 | 50 4B 01 02 | 核心目录文件header标识=(0x02014b50) |
00000031 | 2 | 0A 00 | 压缩所用的pkware版本 |
00000033 | 2 | 0A 00 | 解压所需pkware的最低版本 |
00000035 | 2 | 00 00 | 通用位标记 |
00000037 | 2 | 08 00 | 压缩方法 |
00000039 | 2 | E1 5D | 文件最后修改时间 |
0000003B | 2 | CC 48 | 文件最后修改日期 |
0000003D | 4 | 61 D3 72 09 | CRC-32校验码 |
00000041 | 4 | 08 00 00 00 | 压缩后的大小 |
00000045 | 4 | 06 00 00 00 | 未压缩的大小 |
00000049 | 2 | 07 00 | 文件名长度 |
0000004B | 2 | 00 00 | 扩展域长度 |
0000004D | 2 | 00 00 | 文件注释长度 |
0000004F | 2 | 00 00 | 文件开始位置的磁盘编号 |
00000051 | 2 | 00 00 | 内部文件属性 |
00000053 | 4 | 20 00 00 00 | 外部文件属性 |
00000057 | 4 | 00 00 00 00 | 本地文件header的相对位移 |
0000005B | 7 | 31 32 33 2E 74 78 74 | 目录文件名 |
End of central directory record | |||
00000062 | 4 | 50 4B 05 06 | 核心目录结束标记(0x06054b50) |
00000066 | 2 | 00 00 | 当前磁盘编号 |
00000068 | 2 | 00 00 | 核心目录开始位置的磁盘编号 |
0000006A | 2 | 01 00 | 该磁盘上所记录的核心目录数量 |
0000006C | 2 | 01 00 | 核心目录结构总数 |
0000006E | 4 | 35 00 00 00 | 核心目录的大小 |
00000072 | 4 | 2D 00 00 00 | 核心目录开始位置相对于archive开始的位移 |
00000076 | 2 | 00 00 | 注释长度 |
https://www.cnblogs.com/menlsh/
https://blog.csdn.net/a200710716/article/details/51644421