使用libcurl来下载文件
/*! * Email: scictor@gmail.com * Auth: scictor * Date: 6/9/2020 * File: DownloaderMainT.cpp * Class: %{Cpp:License:ClassName} (if applicable) * variable: * Brief: * Note: */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <curl/curl.h> #include "Downloader.h" #pragma comment(lib,"libcurl.lib") int _tmain(int argc, char* argv[]) { DWORD tick = GetTickCount(); CDownloader murl; DLIO mDlWork; strcpy(mDlWork.url, "http://sw.bos.baidu.com/sw-search-sp/software/f69ab46476e8e/TGPSetup_2.3.2.4083.exe"); strcpy(mDlWork.filePath, ".\\DownloadSoft\\"); murl.AddDownloadWork(mDlWork); //添加到下载任务中 strcpy(mDlWork.url, "http://sw.bos.baidu.com/sw-search-sp/software/16f6d358815f2/iTunes_12.5.1.21.exe"); strcpy(mDlWork.filePath, ".\\DownloadSoft\\"); murl.AddDownloadWork(mDlWork); //添加到下载任务中 murl.StartDownloadThread(); //开启下载线程 CURDI curInfo; double curDownloadLen,preLen = 0.0; while(1) { if(murl.IsDownloadBegin()) { murl.GetCurrentDownloadInfo(&curInfo); //获取每次下载的信息(一次相当于毫秒级,这里速度也用毫秒计算) curDownloadLen = curInfo.CurDownloadLen; printf("正在下载:%s,下载进度:%6.2lf%%,下载速度:%9.2lfKB/s\r",curInfo.fileName, ((double)curInfo.preLocalLen+curInfo.CurDownloadLen)/curInfo.totalFileLen*100,(curDownloadLen-preLen)/(double)(GetTickCount()-tick)); tick = GetTickCount(); Sleep(500); } if(murl.IsDownloadEnd()) break; preLen = curDownloadLen; } return 0; }
/*! * Email: scictor@gmail.com * Auth: scictor * Date: 6/9/2020 * File: Downloader.cpp * Class: Downloader (if applicable) * variable: * Brief: * Note: */ #include "Downloader.h" //#include <io.h> CDownloader::CDownloader(void) { m_downloadCourse = -1; m_nConnectTimeOut = 0; curl_global_init (CURL_GLOBAL_ALL); for(int i=0; i<MAXWORK; i++) { memset(m_dowloadWork->url, 0, 512); memset(m_dowloadWork->filePath, 0, 256); } m_curIndex = 0; } CDownloader::~CDownloader(void) { curl_global_cleanup(); } bool CDownloader::IsDownloadBegin() { if(m_downloadCourse == 0) return true; return false; } bool CDownloader::IsDownloadEnd() { if(m_downloadCourse == 1) return true; return false; } bool CDownloader::CreateMultiDir(const char* pathName) { if(pathName == NULL) return false; char filePath[256] = {0}; strcpy(filePath, pathName); int i = 0, pathLen = strlen(pathName); CString curPath; char curFilePath[256] = {0}; WIN32_FIND_DATA swf; if(filePath[pathLen - 1] != '\\') //最后一个非0字符不是‘\\’则加上 { filePath[pathLen] = '\\'; } while(filePath[i] != '\0') { if(filePath[i] == ':') { i+=2; continue; } if(filePath[i] == '\\') { memcpy(curFilePath, filePath, i); curFilePath[i] = '\0'; curPath = curFilePath; if(FindFirstFile(curPath, &swf) == INVALID_HANDLE_VALUE) //目录不存在就创建 { if(!CreateDirectory(curPath, NULL)) { return false; } } } i++; } return true; } void CDownloader::AddDownloadWork(DLIO downloadWork) { char filePath[256] = {0}; char mUrl[512] = {0}; strcpy(mUrl, downloadWork.url); strcpy(filePath, downloadWork.filePath); int i = strlen(filePath) -1; bool isPath = true; while(filePath[i] != '\\') { if(filePath[i] == '.' && filePath[i+1] != '\0') { isPath = false; } i--; } if(isPath) { if(!CreateMultiDir(filePath)) return; char fileName[256] = {0}; GetFileNameFormUrl(fileName,mUrl); if(filePath[strlen(filePath)-1] != '\\') { strcat(filePath, "\\"); } strcat(filePath, fileName); } else { char realPath[256] = {0}; for(int k=0; k<i; k++) { realPath[k] = filePath[k]; } realPath[i] = '\\'; if(!CreateMultiDir(realPath)) return; } strcpy(m_dowloadWork[m_curIndex].url, mUrl); strcpy(m_dowloadWork[m_curIndex].filePath, filePath); m_curIndex++; } void CDownloader::GetFileNameFormUrl(char* fileName, const char* url) { int urlLen = strlen(url); char mUrl[512] = {0}; char fName[256] = {0}; strcpy(mUrl, url); int cutIndex = 0; int i = urlLen - 1, j = 0; while(mUrl[--i] != '/'); i++; while(mUrl[i] != '\0' && mUrl[i] != '?' &&mUrl[i] != '&') { fName[j++] = mUrl[i++]; } fName[j] = '\0'; strcpy(fileName, fName); return ; } long CDownloader::GetLocalFileLenth(const char* fileName) { if(m_downloadCourse == 0) //文件已经开始下载的时候,取到的是下载前本地文件的大小; return m_curLocalFileLenth; char strTemp[256] = {0}; strcpy(strTemp,fileName); FILE* fp = fopen(strTemp, "rb"); if(fp != NULL) { m_curLocalFileLenth = filelength(fileno(fp)); fclose(fp); return m_curLocalFileLenth; } return 0; } double CDownloader::GetTotalFileLenth(const char* url) { char mUrl[512] = {0}; strcpy(mUrl, url); double downloadFileLenth = 0; CURL* pCurl = curl_easy_init(); curl_easy_setopt(pCurl, CURLOPT_URL, mUrl); curl_easy_setopt(pCurl, CURLOPT_HEADER, 1L); curl_easy_setopt(pCurl, CURLOPT_NOBODY, 1L); if(curl_easy_perform(pCurl) == CURLE_OK) { curl_easy_getinfo(pCurl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &downloadFileLenth); } else { downloadFileLenth = -1; } curl_easy_cleanup(pCurl); return downloadFileLenth; } size_t CDownloader::WriteFunc(char *str, size_t size, size_t nmemb, void *stream) { return fwrite(str, size, nmemb, (FILE*)stream); } size_t CDownloader::ProgressFunc( double* pFileLen, double t,// 下载时总大小 double d, // 已经下载大小 double ultotal, // 上传是总大小 double ulnow) // 已经上传大小 { if(t == 0) return 0; *pFileLen = d; return 0; } int CDownloader::StartDownloadThread() { if(m_downloadCourse == -1||m_downloadCourse == 1) { HANDLE downloadThread = CreateThread(NULL, 0, SingleDownloadProc, this, 0, NULL); CloseHandle(downloadThread); return 0; } return -1; } DWORD WINAPI CDownloader::SingleDownloadProc(LPVOID lpParameter) { CDownloader* pDownload = (CDownloader*)lpParameter; int curDLIndex = 0; CURL* pCurl = curl_easy_init(); while(curDLIndex <= pDownload->m_curIndex) { char fileName[256] = {0}; char url[512] = {0}; strcpy(fileName, pDownload->m_dowloadWork[curDLIndex].filePath); strcpy(url, pDownload->m_dowloadWork[curDLIndex].url); strcpy(pDownload->m_curDownloadInfo.url, url); strcpy(pDownload->m_curDownloadInfo.fileName, fileName); long localFileLen = pDownload->GetLocalFileLenth(fileName); pDownload->m_curLocalFileLenth = localFileLen; pDownload->m_curDownloadInfo.preLocalLen = pDownload->m_curLocalFileLenth; double totalFileLen = pDownload->m_curDownloadInfo.totalFileLen = pDownload->GetTotalFileLenth(url); if(localFileLen >= (long)totalFileLen) //如果需要下载文件的大小大于等于本地文件的大小,直接下载下一个文件 { curDLIndex++; pDownload->m_downloadCourse = -1; continue; } FILE* fp = fopen(fileName,"ab+"); if(fp == NULL) //文件打开错误,进行下一个文件的下载 { pDownload->m_downloadCourse = -1; continue; } curl_easy_setopt(pCurl, CURLOPT_URL, url); curl_easy_setopt(pCurl, CURLOPT_TIMEOUT, pDownload->m_nConnectTimeOut); curl_easy_setopt(pCurl, CURLOPT_HEADER, 0L); curl_easy_setopt(pCurl, CURLOPT_NOBODY, 0L); curl_easy_setopt(pCurl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(pCurl, CURLOPT_RESUME_FROM, localFileLen); curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, WriteFunc); curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, fp); curl_easy_setopt(pCurl, CURLOPT_NOPROGRESS, 0L); curl_easy_setopt(pCurl, CURLOPT_PROGRESSFUNCTION, ProgressFunc); curl_easy_setopt(pCurl, CURLOPT_PROGRESSDATA, &(pDownload->m_curDownloadInfo.CurDownloadLen)); pDownload->m_downloadCourse = 0; if(!curl_easy_perform(pCurl)) { curDLIndex++; pDownload->m_downloadCourse = -1; } fclose(fp); } curl_easy_cleanup(pCurl); pDownload->m_downloadCourse = 1; return 0; } int CDownloader::GetCurrentDownloadInfo(CURDI* lpCurDownloadInfor) { *lpCurDownloadInfor = m_curDownloadInfo; return 0; } int CDownloader::SetConnectTimeOut(DWORD nConnectTimeOut) { if(m_downloadCourse == 0) return -1; else m_nConnectTimeOut = nConnectTimeOut; return 0; }
/*! * Email: scictor@gmail.com * Auth: scictor * Date: 6/9/2020 * File: Downloader.h * Class: Downloader (if applicable) * variable: * Brief: * Note: */ #ifndef DOWNLOADER_H #define DOWNLOADER_H #include <stdio.h> #include <string.h> #include <curl/curl.h> //#include <atlstr.h> #define MAXWORK 200 typedef struct DownloadInfo { char url[512]; char filePath[256]; }DLIO; typedef struct CurDownloadInfor { char url[512]; //url char fileName[256]; //文件名称 long preLocalLen; //本地已下载的长度(大小) double totalFileLen; //文件总长度(大小) double CurDownloadLen; //每次下载的文件长度(大小) }CURDI; class CDownloader { public: CDownloader(void); ~CDownloader(void); int StartDownloadThread(); double GetTotalFileLenth(const char* url); //获取将要下载的文件长度 long GetLocalFileLenth(const char* fileName); //获取本地问价长度 void GetFileNameFormUrl(char* fileName, const char* url); //从URL中获取文件名 void AddDownloadWork(DLIO downloadWork); int SetConnectTimeOut(DWORD nConnectTimeOut); //设置连接的超时时间 int GetCurrentDownloadInfo(CURDI* lpCurDownloadInfor); bool CreateMultiDir(const char* pathName); //是否在本地创建目录,没有就创建 bool IsDownloadBegin(); bool IsDownloadEnd(); protected: static DWORD SingleDownloadProc(LPVOID lpParameter); //线程函数 static size_t WriteFunc(char *str, size_t size, size_t nmemb, void *stream); //写入数据(回调函数) static size_t ProgressFunc(double* fileLen, double t, double d, double ultotal, double ulnow); //下载进度 private: char m_filePath[512]; char m_downloadUrl[256]; int m_downloadCourse; //-1 还未下载 0正在下载 1下载完成 long m_curLocalFileLenth; //因为下载的时候已经计算了本地文件的大小用来设置断点,所以对于每个文件,该数字只会被设置一次;就是下载前的本地大小; long m_nConnectTimeOut; //连接的超时时间 DLIO m_dowloadWork[MAXWORK]; CURDI m_curDownloadInfo; int m_curIndex; CURL* m_pCurl; }; //https://blog.csdn.net/qq_25867649/java/article/details/52789467 #endif // DOWNLOADER_H