Cocos2dx-Lua 使用Curl下载zip压缩文件并解压
生活随笔
收集整理的這篇文章主要介紹了
Cocos2dx-Lua 使用Curl下载zip压缩文件并解压
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
因為工作上的需求要用到異步下載文件并解壓使用,在網上找了一部分資料,發現好多都是零碎的,所以我在這里做個整合。(51開源時代)
首先還是要感謝?@iuoon?大佬提供的CurlDown源碼和?@zsifz?大佬提供的zip解壓源碼,我對源碼進行了一些刪除和修改,如果有需要的可以拿去用,如果有什么修改不足的地方請見諒,這個修改的版本只是適用于我的功能需求。廢話不多說,下面上代碼:
我使用的cocos2dx版本為3.13
CurlDown.h
#pragma once #ifndef __download__CurlDown__ #define __download__CurlDown__ #include <string> #include "cocos2d.h" #include <thread>#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) #include "../../cocos2d-x/external/curl/include/win32/curl/curl.h" #pragma comment(lib, "libcurl_imp.lib") #elif (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) #include "../../cocos2d-x/external/curl/include/android/curl/curl.h" #elif (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) #include "../../cocos2d-x/external/curl/include/ios/curl/curl.h" #endifusing namespace std; USING_NS_CC;/************************************************************************/ /* libcurl download file */ /************************************************************************/ class CurlDown { public:CurlDown();~CurlDown();//入口函數void downStart();//下載控制void downloadControler();//下載bool download();//設置文件信息void setFileInfo(string filePath, string fileName, string downloadUrl);//得到下載進度double getFileDownPercent();//是否下載完成bool isDownLoadFinish();//進度回調void onProgress(double percent/*, string totalSize, string downSize,string speed*/);//下載成功回調void onSuccess(bool isSuccess);//加載zipbool loadZIP(const std::string &zipFilename, const std::string &password/*""*/);//解壓zipbool unCompress(const char * pOutFileName, const std::string &password); public:string mFilePath; // 本地存儲地址string mDownloadUrl; // 下載URLstring mFileName; // 下載文件名稱CURL *libcurl;double mFileDownPercent;//下載文件進度bool m_iFinishState; //是否下載完成 };#endifCurlDown.cpp
#include "CurlDown.h" #include "unzip/unzip.h" #include "cocos/platform/CCFileUtils.h"#define MAX_FILENAME 512 #define BUFFER_SIZE 128CurlDown::CurlDown() :m_iFinishState(false), mFileDownPercent(0) { }CurlDown::~CurlDown() {}void CurlDown::setFileInfo(string filePath, string fileName, string downloadUrl) {mFilePath = filePath;mFileName = fileName;mDownloadUrl = downloadUrl; }static size_t write_func(void *ptr, size_t size, size_t nmemb, void *userdata) {FILE *fp = (FILE*)userdata;size_t written = fwrite(ptr, size, nmemb, fp);return written; }/************************************************************************/ /* 這個回調函數可以告訴我們有多少數據需要傳輸以及傳輸了多少數據,單位是字節。 totalToDownload是需要下載的總字節數(這里不包括本地已下載的一部分),nowDownloaded是已經下載的字節數(指的是totalToDownload中已下載多少)。 totalToUpLoad是將要上傳的字節數,nowUpLoaded是已經上傳的字節數。如果你僅僅下載數據的話,那么ultotal,ulnow將會是0,反之, 如果你僅僅上傳的話,那么dltotal和dlnow也會是0。clientp為用戶自定義參數, 通過設置CURLOPT_XFERINFODATA屬性來傳遞。此函數返回非0值將會中斷傳輸,錯誤代碼是CURLE_ABORTED_BY_CALLBACK */ /************************************************************************/ static int progress_func(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded) {if (totalToDownload <= 0.000001){return 0;}CurlDown* tmpAssets = (CurlDown*)ptr;if (tmpAssets){int tmp = (int)(nowDownloaded / totalToDownload * 100);tmpAssets->onProgress(tmp);}return 0;}void CurlDown::downStart() {m_iFinishState = 0;mFileDownPercent = 0;thread _st_d(&CurlDown::downloadControler, this);//創建一個分支線程_st_d.detach(); }void CurlDown::downloadControler() {bool ret = false;ret = download(); //直接下載log("----ret--------->%d",ret);if (ret){ onSuccess(ret);} }bool CurlDown::download() {FILE *fp = NULL;fp = fopen(mFilePath.c_str(), "wb");if (fp == NULL) {// 如果文件初始化失敗進行返回return false;}CURL *handle = curl_easy_init();libcurl = handle;curl_easy_setopt(handle, CURLOPT_URL, mDownloadUrl.c_str()); curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_func); //寫文件回調方法curl_easy_setopt(handle, CURLOPT_WRITEDATA, fp); // 寫入文件對象curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0);curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, progress_func); //下載進度回調方法curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, this); // 傳入本類對象curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1L); //屏蔽其它信號curl_easy_setopt(handle, CURLOPT_LOW_SPEED_LIMIT, 1L); //控制傳送字節curl_easy_setopt(handle, CURLOPT_LOW_SPEED_TIME, 15); //控制多少秒傳送CURLOPT_LOW_SPEED_LIMITcurl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1); //設置支持302重定向curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, 15); //設置下載時間,超過時間斷開下載,測試模式下把這行注釋可以無時間限制下載CURLcode res = curl_easy_perform(handle);//下載結果if (res == CURLE_OK){long retcode = 0;res = curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &retcode);if (!(res == CURLE_OK && retcode == 200)){CCLOG("downfile-http-faild res:%d code:%ld", res, retcode);m_iFinishState = 2;res = CURL_LAST;}}else{CCLOG("downfile-curl_easy_perform-faild res:%d", res);m_iFinishState = 2;}fclose(fp);return res == CURLE_OK; }void CurlDown::onProgress(double percent/*, string totalSize, string downSize, string speed*/) {mFileDownPercent = percent; }void CurlDown::onSuccess(bool isSuccess) {m_iFinishState = isSuccess; }//是否下載完成 bool CurlDown::isDownLoadFinish() {return m_iFinishState; }//得到下載進度 double CurlDown::getFileDownPercent() {return mFileDownPercent; }bool CurlDown::loadZIP(const std::string &zipFilename, const std::string &password/*""*/) {std::string filename = zipFilename; #if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)std::string dataFilePath = filename; #endif#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS)std::string dataFilePath = FileUtils::getInstance()->getWritablePath() + filename;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//解壓return unCompress(dataFilePath.c_str(), password);//return true; }bool CurlDown::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; }因為我的需求是lua層使用,所以需要注冊到lua層,我使用的方法是使用tolua++編譯pkg文件生成自定義類,然后讓lua腳本使用,本來想直接用cocos2dx自帶的tolua++注冊到lua的,結果搞了半天,都沒有成功,索性就直接用pkg的方式做了。
需要tolua++工具的童鞋自行下載:tolua++編譯pkg腳本工具及CurlDown源碼下載
總結
以上是生活随笔為你收集整理的Cocos2dx-Lua 使用Curl下载zip压缩文件并解压的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 路由与交换实验——eNSP实验
- 下一篇: 黑苹果引导工具:Clover for M