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

2018/04/30 21:42
阅读数 299

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

 

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部