cocos2dx中zip包读取解压使用

来源:互联网 发布:福建广电网络宽带费用 编辑:程序博客网 时间:2024/06/05 20:22

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

1.读取zip

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

bool ResourcesDecode::loadZIP(const std::string &zipFilename,const std::string &password/*""*/){    std::string filename = zipFilename;    std::string dataFilePath = FileUtils::getInstance()->getWritablePath() + filename;    #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS)    if(access(dataFilePath.c_str(), 0) != 0)    {        std::string strPath = FileUtils::getInstance()->fullPathForFilename(filename);        ssize_t len = 0;        unsigned char *data = 0;        CCLOG("strPath:%s",strPath.c_str());        data = FileUtils::getInstance()->getFileData(strPath.c_str(), "r", &len);        CCLOG("file:%s, len:%zd", dataFilePath.c_str(), len);        FILE* fp = fopen(dataFilePath.c_str(), "w+");        if(!fp)        {            CCLOG("file not found!");        }        fwrite(data, sizeof(char), len, fp);        fclose(fp);        delete []data;        data = 0;    }#endif    //解压    unCompress(dataFilePath.c_str(),password);    return true;}
上面参数中password为zip压缩文件密码,在使用资源之前调用loadZIP即可

2.解压zip

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

bool ResourcesDecode::unCompress(const char * pOutFileName,const std::string &password){    if (!pOutFileName) {        CCLOG("unCompress() - invalid arguments");        return 0;    }    FileUtils *utils = FileUtils::getInstance();    std::string outFileName = utils->fullPathForFilename(pOutFileName);    // 打开压缩文件    unzFile zipfile = unzOpen(outFileName.c_str());    if (! zipfile)    {        CCLOG("can not open downloaded zip file %s", outFileName.c_str());        return false;    }    // 获取zip文件信息    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;    }    // 临时缓存,用于从zip中读取数据,然后将数据给解压后的文件    char readBuffer[BUFFER_SIZE];    //开始解压缩    CCLOG("start uncompressing");    //根据自己压缩方式修改文件夹的创建方式    std::string storageDir;    int pos = outFileName.find_last_of("/");    storageDir = outFileName.substr(0,pos);//    FileUtils::getInstance()->createDirectory(storageDir);        // 循环提取压缩包内文件    // global_info.number_entry为压缩包内文件个数    uLong i;    for (i = 0; i < global_info.number_entry; ++i)    {        // 获取压缩包内的文件名        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 fullPath = storageDir + "/"+fileName;                // 检测路径是文件夹还是文件        const size_t filenameLength = strlen(fileName);        if (fileName[filenameLength-1] == '/')        {            // 该文件是一个文件夹,那么就创建它            if (!FileUtils::getInstance()->createDirectory(fullPath.c_str()))            {                CCLOG("can not create directory %s", fullPath.c_str());                unzClose(zipfile);                return false;            }        }        else        {            // 该文件是一个文件,那么就提取创建它            if(password.empty())            {                if (unzOpenCurrentFile(zipfile) != UNZ_OK)                {                    CCLOG("can not open file %s", fileName);                    unzClose(zipfile);                    return false;                }            }else            {                if (unzOpenCurrentFilePassword(zipfile,password.c_str())!=UNZ_OK)                {                    CCLOG("can not open file %s", fileName);                    unzClose(zipfile);                    return false;                }            }                        // 创建目标文件            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;            }                        // 将压缩文件内容写入目标文件            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);                // 如果zip内还有其他文件,则将当前文件指定为下一个待解压的文件        if ((i+1) < global_info.number_entry)        {            if (unzGoToNextFile(zipfile) != UNZ_OK)              {                  CCLOG("can not read next file");                unzClose(zipfile);                  return false;              }          }      }    //压缩完毕    CCLOG("end uncompressing");        //压缩完毕删除zip文件,删除前要先关闭    unzClose(zipfile);    if (remove(outFileName.c_str()) != 0)    {        CCLOG("can not remove downloaded zip file %s", outFileName.c_str());    }    return true;}

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

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

3.读取zip内容

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

if(isPopupNotify()){        if (fullpath.empty())        {            fullpath = ResourcesDecode::getInstance()->findPathWithZip(filename);            if (fullpath.size() == 0)            {                return "";            }            return fullpath;        }        CCLOG("cocos2d: fullPathForFilename: No file found at %s. Possible missing file.", filename.c_str());    }

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

std::string dataFilePath = FileUtils::getInstance()->getWritablePath() + filename;    if(access(dataFilePath.c_str(), 0) != 0)    {        CCLOG("not find in Documents:%s",filename.c_str());        return "";    }    return dataFilePath;
经过上面处理即可获取到正常的资源。

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

0 0