将libcurl封装下载类

  

 

 

这里我将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源码,就会编译出来!

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值