最近遇到需要在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
|
请发表评论