1. 程式人生 > >使用libcurl下載檔案小例

使用libcurl下載檔案小例

libcurl是一個很強大的開源網路處理庫,支援包括HTTP、HTTPS、FTP……一系列網路協議。用它來進行HTTP的get\post 或者下載檔案更是小菜一碟,chrome核心都用到了它,本文主要講解一個使用curl下載檔案的小例。

首先是去下載curl的最新原始碼,然後編譯成動態庫或者靜態庫;然後把標頭檔案和庫檔案拿出來加入到我們自己的工程中,引用宣告:

#include "curl.h"
#ifdef _DEBUG
#pragma comment(lib, "../Debug/libcurld")
#else
#pragma comment(lib, "../Release/libcurl")
#endif
特意在原有程式碼上加了一些註釋,希望可以更好理解,上程式碼:
<pre name="code" class="cpp">// UseLibCurl.cpp : 定義控制檯應用程式的入口點。
//

#include "stdafx.h"
#include <Windows.h>
#include <CommCtrl.h>
#include "resource.h"
#include "curl.h"
#ifdef _DEBUG
#pragma comment(lib, "../Debug/libcurld")
#else
#pragma comment(lib, "../Release/libcurl")
#endif


//這個用來儲存對話方塊的視窗控制代碼,因為後面要向這個視窗發訊息,必須知道其視窗控制代碼
HWND	g_hDlgWnd = NULL;
//提供給CURL下載進度回撥的函式,用於儲存下載的資料到檔案
static size_t	DownloadCallback(void* pBuffer, size_t nSize, size_t nMemByte, void* pParam);
//提供給CURL下載進度回撥的函式,用於計算下載進度通知介面
static int ProgressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
//這是對話方塊的訊息迴圈,在控制檯程式裡面建立GUI,僅僅是為了更好地展現下載回撥這個功能
INT_PTR CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
//這個是下載的執行緒函式,為了不把對話方塊主介面卡死,肯定是要自己開執行緒來下載的了
DWORD WINAPI DownloadThread(LPVOID lpParam);

int _tmain(int argc, _TCHAR* argv[])
{
	//彈出對話方塊,知道對話方塊關閉才會執行退出
	DialogBox(NULL, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DialogProc );
	return 0;
}

static size_t DownloadCallback(void* pBuffer, size_t nSize, size_t nMemByte, void* pParam)
{
	//把下載到的資料以追加的方式寫入檔案(一定要有a,否則前面寫入的內容就會被覆蓋了)
	FILE* fp = NULL;
	fopen_s(&fp, "c:\\test.apk", "ab+");
	size_t nWrite = fwrite(pBuffer, nSize, nMemByte, fp);
	fclose(fp);
	return nWrite;
}

static int ProgressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
{
	if ( dltotal > -0.1 && dltotal < 0.1 )
		return 0;
	int nPos = (int) ( (dlnow/dltotal)*100 );
	//通知進度條更新下載進度
	::PostMessage(g_hDlgWnd, WM_USER + 110, nPos, 0);
	//::Sleep(10);
	return 0;
}

INT_PTR CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch( uMsg )
	{
	case WM_INITDIALOG:
		{
			g_hDlgWnd = hWnd;
			HWND hProgress = GetDlgItem(hWnd, IDC_PROGRESS1);
			SendMessage(hProgress, PBM_SETRANGE32, (WPARAM) 0, (LPARAM) 100);
			//對話方塊初始化時建立下載執行緒
			HANDLE hThread = CreateThread(NULL, 0, DownloadThread, 0, 0, NULL);
			CloseHandle(hThread);
			::SetWindowText(hWnd, L"使用CURL下載檔案示例:");
			return TRUE;
		}
	case WM_COMMAND:
		{
			WORD  msg = HIWORD(wParam);
			WORD  id  = LOWORD(wParam);
			if ( id == IDOK || id == IDCANCEL )
				EndDialog(hWnd, id);
			break;
		}
	case WM_ERASEBKGND:
		return TRUE;
	case WM_CTLCOLORSTATIC:
		return (INT_PTR)(HBRUSH)::GetStockObject(WHITE_BRUSH);
	case WM_USER + 110:
		{//接收到設定進度的訊息
			HWND	hProgress	= GetDlgItem(hWnd, IDC_PROGRESS1);
			HWND	hStatus		= GetDlgItem(hWnd, IDC_STATUS);
			if ( hProgress )
				SendMessage(hProgress, PBM_SETPOS, wParam, 0L);
			if ( hStatus )
			{
				WCHAR szBuffer[100] = {0};
				if ( wParam<100 )
					swprintf(szBuffer, L"正在下載檔案,進度:%d%%", wParam);
				else
					swprintf(szBuffer, L"檔案下載完畢!");
				::SetWindowText(hStatus, szBuffer);
			}
			return 0;
		}
	default:
		break;
	}
	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

DWORD WINAPI DownloadThread(LPVOID lpParam)
{
	//初始化curl,這個是必須的
	CURL* curl = curl_easy_init();
	curl_easy_setopt(curl, CURLOPT_URL, "http://android.shoujids.com/software/download?id=154103");
	//設定接收資料的回撥
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, DownloadCallback);
	//curl_easy_setopt(curl, CURLOPT_INFILESIZE, lFileSize);
	//curl_easy_setopt(curl, CURLOPT_HEADER, 1);
	//curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
	//curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
	// 設定重定向的最大次數
	curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5);
	// 設定301、302跳轉跟隨location
	curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
	//設定進度回撥函式
	curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, ProgressCallback);
	//curl_easy_getinfo(curl,  CURLINFO_CONTENT_LENGTH_DOWNLOAD, &lFileSize);
	//curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, g_hDlgWnd);
	//開始執行請求
	CURLcode retcCode = curl_easy_perform(curl);
	//檢視是否有出錯資訊
	const char* pError = curl_easy_strerror(retcCode);
	//清理curl,和前面的初始化匹配
	curl_easy_cleanup(curl);
	return 0;
}


執行效果圖: