libcurl断点下载
开发需要写了一个处理curl 下载的c++类,内含有多个静态方法和实例方法,写在这里留给有需求的同学
头文件 CURLHelper.h enum CURLHelperStateType { CURLHelper_START = 0, CURLHelper_PROGRESS = 1, CURLHelper_COMPLETE = 2, CURLHelper_UNKNOW = 99 }; class CURLHelper { public: static std::string getHttpString(const char * url); static long getDownloadFileSize(const char *url); static long getLocalFileSize(const char *localpath); CURLHelper(); ~CURLHelper(); void downloadFile(const char *url,const char *localpath); void downloadProgressCallback(double percent); long getTotalFileSize(); CURLHelperStateType getState(); double getPercent(); void doDownload(); private: string m_url; string m_local_path; double m_fileTotalSize; // double m_currentFileSize; double m_percent; pthread_t *pDownloadThread; int reDownloadCount; CURLHelperStateType m_currentState; };
/** * 获取服务器文件的字符 ,阻塞式 * @param url * @return */ string CURLHelper::getHttpString(const char *url) { std::string str = ""; CURL *_curl = curl_easy_init(); if (! _curl) { CCLOG("can not init curl"); return str; } curl_easy_setopt(_curl, CURLOPT_URL, url); curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, getCharCode); curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &str); CURLcode res = curl_easy_perform(_curl); if (res != CURLE_OK) { CCLOG("can not get version file content, error code is %d", res); curl_easy_cleanup(_curl); return str; } curl_easy_cleanup(_curl); return str; } /** * 获取服务器上的文件物理大小 * @param url * @return */ long CURLHelper::getDownloadFileSize(const char *url) { double downloadFileLenth = 0; CURL *handle = curl_easy_init(); curl_easy_setopt(handle, CURLOPT_URL, url); curl_easy_setopt(handle, CURLOPT_HEADER, 1); //只需要header头 curl_easy_setopt(handle, CURLOPT_NOBODY, 1); //不需要body if (curl_easy_perform(handle) == CURLE_OK) { curl_easy_getinfo(handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &downloadFileLenth); } else { downloadFileLenth = -1; } return downloadFileLenth; } /** * 获取本地文件大小 * @param localpath * @return */ long CURLHelper::getLocalFileSize(const char *localpath) { curl_off_t local_file_len = 0; struct stat file_info; if(stat(localpath, &file_info) == 0) { local_file_len = file_info.st_size; } return local_file_len; } /* 保存下载文件 */ size_t wirtefunc(void *ptr, size_t size, size_t nmemb, void *stream) { FILE *fp = (FILE*)stream; size_t written = fwrite(ptr, size, nmemb, fp); return written; } /* 下载回调的计算进度条的函数 */ static int progress_func(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded) { CURLHelper *helper = (CURLHelper*)ptr; double curpercent = 100 * nowDownloaded / totalToDownload; helper->downloadProgressCallback(curpercent); return 0; } void CURLHelper::doDownload() { do { string tmpPath = m_local_path + ".tmp"; FILE *localFile = NULL; double m_currentTmpSize = CURLHelper::getLocalFileSize(tmpPath.c_str()); if (m_currentTmpSize > 0) { localFile = fopen(tmpPath.c_str(), "ab+"); CCLOG("断点下载模式"); } else { localFile = fopen(tmpPath.c_str(), "wb+"); } int cc = error_no(); if (!localFile) { break; } m_currentState = CURLHelper_PROGRESS; CURL *curlhandle = curl_easy_init(); curl_easy_setopt(curlhandle, CURLOPT_URL, m_url.c_str()); //写函数回调 curl_easy_setopt(curlhandle, CURLOPT_WRITEDATA, localFile); curl_easy_setopt(curlhandle, CURLOPT_WRITEFUNCTION, wirtefunc); //断点下载 curl_easy_setopt(curlhandle, CURLOPT_RESUME_FROM_LARGE, m_currentTmpSize); //下载进度回调 curl_easy_setopt(curlhandle, CURLOPT_NOPROGRESS, 0L); curl_easy_setopt(curlhandle, CURLOPT_PROGRESSFUNCTION, progress_func); curl_easy_setopt(curlhandle, CURLOPT_PROGRESSDATA, this); CURLcode res = curl_easy_perform(curlhandle); fclose(localFile); curl_easy_cleanup(curlhandle); if (res == CURLE_OK) { //文件改名 int result = rename(tmpPath.c_str(), m_local_path.c_str()); int e = error_no(); if (result == 0) { CCLOG("改名成功"); } else { CCLOG("rename failed %d",e); } } else { CCLOG("下载失败,CURLcode %d",res); if (reDownloadCount < 3) { //直接删除缓存文件 int removeCode = remove(tmpPath.c_str()); CCLOG("下载失败,删除tmp文件,并重新下载 %d",removeCode); reDownloadCount++; m_currentState = CURLHelper_START; doDownload(); return; } } } while (0); m_currentState = CURLHelper_COMPLETE; } CURLHelper::CURLHelper() { m_currentState = CURLHelper_UNKNOW; pDownloadThread = NULL; m_percent = 0; reDownloadCount = 0; } CURLHelper::~CURLHelper() { CCLOG("~CURLHelper"); if (pDownloadThread) { delete pDownloadThread; } } long CURLHelper::getTotalFileSize() { return m_fileTotalSize; } CURLHelperStateType CURLHelper::getState() { return m_currentState; } static void *thread_downloadFiles(void* data) { CURLHelper *helper = (CURLHelper*)data; helper->doDownload(); return NULL; } void CURLHelper::downloadFile(const char *url, const char *localpath) { m_url = url; m_local_path = localpath; m_fileTotalSize = CURLHelper::getDownloadFileSize(url); m_percent = 0; //记录当前状态 m_currentState = CURLHelper_START; //开启线程下载 pDownloadThread = new pthread_t(); pthread_create(&(*pDownloadThread), NULL, thread_downloadFiles, (void*)this); } void CURLHelper::downloadProgressCallback(double percent) { m_percent = percent; } double CURLHelper::getPercent() { return m_percent; }