cocos2dx中zip包读取解压使用

记录一下在cocos2dx中读取zip和解压zip

1.读取zip

获取可读写入路径,把zip文件拷到可读写路径下,如下

[cpp]  view plain  copy
  1. bool ResourcesDecode::loadZIP(const std::string &zipFilename,const std::string &password/*""*/)  
  2. {  
  3.     std::string filename = zipFilename;  
  4.     std::string dataFilePath = FileUtils::getInstance()->getWritablePath() + filename;  
  5.       
  6. #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS)  
  7.     if(access(dataFilePath.c_str(), 0) != 0)  
  8.     {  
  9.         std::string strPath = FileUtils::getInstance()->fullPathForFilename(filename);  
  10.         ssize_t len = 0;  
  11.         unsigned char *data = 0;  
  12.         CCLOG("strPath:%s",strPath.c_str());  
  13.         data = FileUtils::getInstance()->getFileData(strPath.c_str(), "r", &len);  
  14.         CCLOG("file:%s, len:%zd", dataFilePath.c_str(), len);  
  15.         FILE* fp = fopen(dataFilePath.c_str(), "w+");  
  16.         if(!fp)  
  17.         {  
  18.             CCLOG("file not found!");  
  19.         }  
  20.         fwrite(data, sizeof(char), len, fp);  
  21.         fclose(fp);  
  22.         delete []data;  
  23.         data = 0;  
  24.     }  
  25. #endif  
  26.     //解压  
  27.     unCompress(dataFilePath.c_str(),password);  
  28.     return true;  
  29. }  
上面参数中password为zip压缩文件密码,在使用资源之前调用loadZIP即可

2.解压zip

读取zip到内存,并且解压zip,如下

[cpp]  view plain  copy
  1. bool ResourcesDecode::unCompress(const char * pOutFileName,const std::string &password)  
  2. {  
  3.     if (!pOutFileName) {  
  4.         CCLOG("unCompress() - invalid arguments");  
  5.         return 0;  
  6.     }  
  7.     FileUtils *utils = FileUtils::getInstance();  
  8.     std::string outFileName = utils->fullPathForFilename(pOutFileName);  
  9.     // 打开压缩文件  
  10.     unzFile zipfile = unzOpen(outFileName.c_str());  
  11.     if (! zipfile)  
  12.     {  
  13.         CCLOG("can not open downloaded zip file %s", outFileName.c_str());  
  14.         return false;  
  15.     }  
  16.     // 获取zip文件信息  
  17.     unz_global_info global_info;  
  18.     if (unzGetGlobalInfo(zipfile, &global_info) != UNZ_OK)  
  19.     {  
  20.         CCLOG("can not read file global info of %s", outFileName.c_str());  
  21.         unzClose(zipfile);  
  22.         return false;  
  23.     }  
  24.     // 临时缓存,用于从zip中读取数据,然后将数据给解压后的文件  
  25.     char readBuffer[BUFFER_SIZE];  
  26.     //开始解压缩  
  27.     CCLOG("start uncompressing");  
  28.     //根据自己压缩方式修改文件夹的创建方式  
  29.     std::string storageDir;  
  30.     int pos = outFileName.find_last_of("/");  
  31.     storageDir = outFileName.substr(0,pos);  
  32. //    FileUtils::getInstance()->createDirectory(storageDir);  
  33.       
  34.     // 循环提取压缩包内文件  
  35.     // global_info.number_entry为压缩包内文件个数  
  36.     uLong i;  
  37.     for (i = 0; i < global_info.number_entry; ++i)  
  38.     {  
  39.         // 获取压缩包内的文件名  
  40.         unz_file_info fileInfo;  
  41.         char fileName[MAX_FILENAME];  
  42.         if (unzGetCurrentFileInfo(zipfile,  
  43.                                   &fileInfo,  
  44.                                   fileName,  
  45.                                   MAX_FILENAME,  
  46.                                   NULL,  
  47.                                   0,  
  48.                                   NULL,  
  49.                                   0) != UNZ_OK)  
  50.         {  
  51.             CCLOG("can not read file info");  
  52.             unzClose(zipfile);  
  53.             return false;  
  54.         }  
  55.           
  56.         //该文件存放路径  
  57.         std::string fullPath = storageDir + "/"+fileName;  
  58.           
  59.         // 检测路径是文件夹还是文件  
  60.         const size_t filenameLength = strlen(fileName);  
  61.         if (fileName[filenameLength-1] == '/')  
  62.         {  
  63.             // 该文件是一个文件夹,那么就创建它  
  64.             if (!FileUtils::getInstance()->createDirectory(fullPath.c_str()))  
  65.             {  
  66.                 CCLOG("can not create directory %s", fullPath.c_str());  
  67.                 unzClose(zipfile);  
  68.                 return false;  
  69.             }  
  70.         }  
  71.         else  
  72.         {  
  73.             // 该文件是一个文件,那么就提取创建它  
  74.             if(password.empty())  
  75.             {  
  76.                 if (unzOpenCurrentFile(zipfile) != UNZ_OK)  
  77.                 {  
  78.                     CCLOG("can not open file %s", fileName);  
  79.                     unzClose(zipfile);  
  80.                     return false;  
  81.                 }  
  82.             }else  
  83.             {  
  84.                 if (unzOpenCurrentFilePassword(zipfile,password.c_str())!=UNZ_OK)  
  85.                 {  
  86.                     CCLOG("can not open file %s", fileName);  
  87.                     unzClose(zipfile);  
  88.                     return false;  
  89.                 }  
  90.             }  
  91.               
  92.             // 创建目标文件  
  93.             FILE *out = fopen(fullPath.c_str(), "wb");  
  94.             if (! out)  
  95.             {  
  96.                 CCLOG("can not open destination file %s", fullPath.c_str());  
  97.                 unzCloseCurrentFile(zipfile);  
  98.                 unzClose(zipfile);  
  99.                 return false;  
  100.             }  
  101.               
  102.             // 将压缩文件内容写入目标文件  
  103.             int error = UNZ_OK;  
  104.             do  
  105.             {  
  106.                 error = unzReadCurrentFile(zipfile, readBuffer, BUFFER_SIZE);  
  107.                 if (error < 0)  
  108.                 {  
  109.                     CCLOG("can not read zip file %s, error code is %d", fileName, error);  
  110.                     unzCloseCurrentFile(zipfile);  
  111.                     unzClose(zipfile);  
  112.                     return false;  
  113.                 }  
  114.                 if (error > 0)  
  115.                 {  
  116.                     fwrite(readBuffer, error, 1, out);  
  117.                 }  
  118.             } while(error > 0);  
  119.               
  120.             fclose(out);  
  121.         }  
  122.         //关闭当前被解压缩的文件  
  123.         unzCloseCurrentFile(zipfile);  
  124.           
  125.         // 如果zip内还有其他文件,则将当前文件指定为下一个待解压的文件  
  126.         if ((i+1) < global_info.number_entry)  
  127.         {  
  128.             if (unzGoToNextFile(zipfile) != UNZ_OK)    
  129.             {    
  130.                 CCLOG("can not read next file");  
  131.                 unzClose(zipfile);    
  132.                 return false;    
  133.             }    
  134.         }    
  135.     }  
  136.     //压缩完毕  
  137.     CCLOG("end uncompressing");  
  138.       
  139.     //压缩完毕删除zip文件,删除前要先关闭  
  140.     unzClose(zipfile);  
  141.     if (remove(outFileName.c_str()) != 0)  
  142.     {  
  143.         CCLOG("can not remove downloaded zip file %s", outFileName.c_str());  
  144.     }  
  145.     return true;  
  146. }  

在有password密码时使用的是unzip的unzOpenCurrentFilePassword调用的 unzOpenCurrentFile3,听说zlib库被某某某机构下令不准加密,有可能这样所以cocos2dx就在unzip.cpp的开头定义了
[cpp]  view plain  copy
  1. #ifndef NOUNCRYPT  
  2.         #define NOUNCRYPT  
  3. #endif  
unzOpenCurrentFile3中做了
[cpp]  view plain  copy
  1. #    ifndef NOUNCRYPT  
  2.     char source[12];  
  3. #    else  
  4.     if (password != NULL)  
  5.         return UNZ_PARAMERROR;  
  6. #    endif  

所以在开头注释掉#define NOUNCRYPT,这样就可以正常解压了

3.读取zip内容

因为解压出来的zip下内容的路径与正常读取资源时的路径不同,所以需要修改一下FileUtils::fullPathForFilename下的路径读取,只需要做如下修改

[cpp]  view plain  copy
  1. if(isPopupNotify()){  
  2.         if (fullpath.empty())  
  3.         {  
  4.             fullpath = ResourcesDecode::getInstance()->findPathWithZip(filename);  
  5.             if (fullpath.size() == 0)  
  6.             {  
  7.                 return "";  
  8.             }  
  9.             return fullpath;  
  10.         }  
  11.         CCLOG("cocos2d: fullPathForFilename: No file found at %s. Possible missing file.", filename.c_str());  
  12.     }  

当fullPathForFilename本身处理后的fullpath为空的时候,就去执行findPathWithzip方法,如下

[cpp]  view plain  copy
  1. std::string dataFilePath = FileUtils::getInstance()->getWritablePath() + filename;  
  2.     if(access(dataFilePath.c_str(), 0) != 0)  
  3.     {  
  4.         CCLOG("not find in Documents:%s",filename.c_str());  
  5.         return "";  
  6.     }  
  7.     return dataFilePath;  
经过上面处理即可获取到正常的资源。

本文参考总结了一些文章,互相借鉴,有啥不对和优化的地方,欢迎评论,下篇写一下cocos2dx中用到的xxtea加密。

你可能感兴趣的:(Cocos2d-x)