这里我将libcurl封装成了DLL,可以通过导出类指针进行函数调用,可以进行下载暂停、下载恢复、断点续传、获取下载速度、进度等等功能,不多说,上代码!
DownloadDLL.h
#pragma once
#ifdef DLL_DOWNLOAD
#define DLLAPI _declspec(dllexport)
#else
#define DLLAPI _declspec(dllimport)
#endif
#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 DLLAPI 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); //获取当前下载信息
double GetDownloadSpeed(); //获取下载速度
double GetDownloadProgress(); //获取下载进度
BOOL CreateMultiDir(const char* pathName); //是否在本地创建目录,没有就创建
BOOL IsDownloadBegin(); //下载是否开始
BOOL IsDownloadEnd(); //下载是否结束
void DownloadBegin(); //下载开始
void DownloadPause(); //下载暂停
void DownloadResume(); //恢复下载
void ExitDownload(); //退出下载
protected:
static DWORD WINAPI 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;
double preLen;
DWORD tick; //毫秒级
};
extern "C" DLLAPI CDownloader* GetCDownload(); //获取类CDownloader的对象
DownloadDLL.cpp
#define DLL_DOWNLOAD
#include "DownLoadDLL.h"
#include <io.h>
#pragma comment(lib,"libcurl.lib")
static BOOL m_bIsStop = FALSE; //是否下载暂停
//////////头文件中函数的实现
CDownloader::CDownloader(void)
{
m_downloadCourse = -1;
m_nConnectTimeOut = 0;
tick = GetTickCount();
preLen = 0.0;
curl_global_init (CURL_GLOBAL_ALL);
for(int i=0; i<MAXWORK; i++)
{
memset(m_dowloadWork[i].url, 0, 512);
memset(m_dowloadWork[i].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)
{
//从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)
{
//回调函数这有个问题就是函数的返回值 ,必须返回size*nmemb,否则只调用一次
//然后直接跳出回调函数,导致HTTP接收失败。不知道为什么
if(m_bIsStop == TRUE)
return 0;
else
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();
pDownload->m_pCurl = curl_easy_init();
while(curDLIndex <= pDownload->m_curIndex)
{
// if(m_bIsStop == TRUE)
// {
// curl_easy_cleanup(pDownload->m_pCurl);
// return 0;
// }
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(pDownload->m_pCurl, CURLOPT_URL, url);
curl_easy_setopt(pDownload->m_pCurl, CURLOPT_TIMEOUT, pDownload->m_nConnectTimeOut);
curl_easy_setopt(pDownload->m_pCurl, CURLOPT_HEADER, 0L);
curl_easy_setopt(pDownload->m_pCurl, CURLOPT_NOBODY, 0L);
curl_easy_setopt(pDownload->m_pCurl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(pDownload->m_pCurl, CURLOPT_RESUME_FROM_LARGE, localFileLen);
curl_easy_setopt(pDownload->m_pCurl, CURLOPT_WRITEFUNCTION, WriteFunc);
curl_easy_setopt(pDownload->m_pCurl, CURLOPT_WRITEDATA, fp);
curl_easy_setopt(pDownload->m_pCurl, CURLOPT_NOPROGRESS, 0L);
curl_easy_setopt(pDownload->m_pCurl, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
curl_easy_setopt(pDownload->m_pCurl, CURLOPT_PROGRESSDATA, &(pDownload->m_curDownloadInfo.CurDownloadLen));
pDownload->m_downloadCourse = 0;
if(!curl_easy_perform(pDownload->m_pCurl))
{
curDLIndex++;
pDownload->m_downloadCourse = -1;
}
fclose(fp);
}
curl_easy_cleanup(pDownload->m_pCurl);
m_bIsStop = FALSE;
pDownload->m_downloadCourse = 1;
return 0;
}
void CDownloader::DownloadBegin()
{
//开始下载
if(m_downloadUrl)
{
StartDownloadThread();
m_bIsStop = FALSE;
}
else
{
MessageBox(NULL,_T("下载地址为空!"),_T("提示"),NULL);
return ;
}
}
void CDownloader::DownloadPause()
{
//暂停下载
if(m_pCurl)
curl_easy_pause(m_pCurl,CURLPAUSE_RECV);
}
void CDownloader::DownloadResume()
{
//恢复下载
if(m_pCurl)
curl_easy_pause(m_pCurl,CURLPAUSE_RECV_CONT);
}
void CDownloader::ExitDownload()
{
//退出下载
if(m_pCurl)
{
m_bIsStop = TRUE;
}
}
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;
}
double CDownloader::GetDownloadSpeed()
{
//获取下载速度
CURDI info;
GetCurrentDownloadInfo(&info);
double curLen;
curLen = info.CurDownloadLen;
double dSpd;
dSpd = (curLen-preLen)/(double)(GetTickCount()-tick);
return dSpd;
}
double CDownloader::GetDownloadProgress()
{
//获取下载进度
CURDI info;
GetCurrentDownloadInfo(&info);
double info_progress;
info_progress = ((double)info.preLocalLen + info.CurDownloadLen)/info.totalFileLen*100;
return info_progress;
}
extern "C" DLLAPI CDownloader* GetCDownload()
{
return new CDownloader();
}
这个dll库需要支持libcurl.dll和libcurl.lib,还有curl文件夹!这些可以下载libcurl源码,就会编译出来!