cocos lua解压zip文件(支持源文件非zip格式)

最近遇到需要在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 ,也就是:

1
2
3
4
ZipFile *zip = nullptr;
if (zipFileData) {
    zip = ZipFile::createWithBuffer(zipFileData, size);
}

 

1
这样就ok。同时了解了下zip格式:

 

 

OffsetBytesContentsDescriptor
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

 

posted @   lesten  阅读(2646)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示