最近遇到需要在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