[libcurl]_[0基础]_[使用libcurl下载大文件]

场景:

1. 在Windows编程时, 下载http页面(html,xml)能够使用winhttp库,可是并非非常下载文件,由于会失败. 由此引出了WinINet库,无奈这个库的稳定性比較低,使用样例又少,

下载大文件时常常是不完整,可查找的资料非常少或者是没有特殊情况的解决的方法。

2. 我的原则是假设系统有自带的就用系统的,可是 WinINet 要掌握须要花不少时间. 时间因素考虑到了libcurl.

3. libcurl支持ftp,http等协议的文件读取,还能自己主动获取文件大小, 最重要的是不须要怎么改动就能稳定支持完整下载大文件,还能支持跨平台(Windows,MacOSX)。

參考编译后的curl.exe使用:

curl.exe -O http://img.ptcms.csdn.net/article/201506/25/558bbe1baed6e.jpg

之前也有写libcurl的使用的其它场景:

[libcurl]_[C/C++]_[使用libcurl库做简单软件更新解决方式]

编译mingw库非常容易,直接依赖windows本地库即可,要编译msvc版本号的话须要进入 winbuild 文件夹,參考 BUILD.WINDOWS.txt 里的

nmake /f Makefile.vc mode=<static or dll> <options>

我用的配置

nmake /f Makefile.vc mode=dll VC=10 ENABLE_IDN=no

http_download_domain.h

#ifndef __HTTP_DOWNLOAD_DOMAIN
#define __HTTP_DOWNLOAD_DOMAIN

#include <string>
#include "curl/curl.h"

class HttpDownloadDomain
{
public:
	HttpDownloadDomain(bool* cancel);
	~HttpDownloadDomain();
	bool DownloadFile(std::string url,std::wstring path);
	bool *cancel_;

private:

	static size_t DownloadCallback(void* pBuffer, size_t nSize, size_t nMemByte, void* pParam);
	static int ProgressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);

};

#endif

http_download_domain.cpp

#include "stdafx.h"

#include "http_download_domain.h"

#include <iostream>

HttpDownloadDomain::HttpDownloadDomain(bool* cancel)
{
	cancel_ = cancel;
}

HttpDownloadDomain::~HttpDownloadDomain()
{
}

size_t HttpDownloadDomain::DownloadCallback(void* pBuffer, size_t nSize, size_t nMemByte, void* pParam)
{
    FILE* fp = (FILE*)pParam;
    size_t nWrite = fwrite(pBuffer, nSize, nMemByte, fp);  

    return nWrite;
}  

int HttpDownloadDomain::ProgressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
{
	HttpDownloadDomain* dd = (HttpDownloadDomain*)clientp;

    if ( dltotal > -0.1 && dltotal < 0.1 )
    {
		return 0;
	}
    int nPos = (int) ( (dlnow/dltotal)*100 );
    //通知进度条更新下载进度
    std::cout << "dltotal: " << (long)dltotal << " ---- dlnow:" << (long)dlnow << std::endl;

	if(*dd->cancel_)
	{
		//1. 返回非0值就会终止 curl_easy_perform 运行
		return -2;
	}
    return 0;
}

bool HttpDownloadDomain::DownloadFile(std::string URLADDR,std::wstring path)
{
	//初始化curl,这个是必须的
    CURL *curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_URL, URLADDR.c_str());  

    //设置接收数据的回调
	FILE* file = _wfopen(path.c_str(), L"wb");
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, DownloadCallback);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA,file);
    curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5);
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
    curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, ProgressCallback);
	curl_easy_setopt(curl, CURLOPT_PROGRESSDATA,this);
    CURLcode retcCode = curl_easy_perform(curl);

    const char* pError = curl_easy_strerror(retcCode);
	std::cout << "pError: " << pError << std::endl;
	fclose(file);
    //清理curl,和前面的初始化匹配
    curl_easy_cleanup(curl);

	return !retcCode;
}

使用方式:

#include "stdafx.h"

#include "http_download_domain.h"

int _tmain(int argc, _TCHAR* argv[])
{
	bool i = 0;
    HttpDownloadDomain hdd(&i);
	hdd.DownloadFile("http://img.ptcms.csdn.net/article/201506/25/558bbe1baed6e.jpg",L"C:\\Users\\apple\\Downloads\\558bbe1baed6e.jpg");
    system("pause");
	return 0;
}

下载完整样例:

http://download.csdn.net/detail/infoworld/8840787

时间: 2024-10-08 19:35:01

[libcurl]_[0基础]_[使用libcurl下载大文件]的相关文章

[wxWidgets]_[0基础]_[经常更新进度条程序]

场景: 1. 非常根据程序的进展需要处理业务,以更新进度条,进度条的目的是为了让用户知道业务流程的进度.一个进度条程序更友好,让用户知道在程序执行.不是没有反应. 2. 现在更新见过这两种方法的进展.事件(信号,队列)的发送让主线程依照发送的顺序来更新进度条,一种是设置一个全局整形变量, 通过执行定时器的方式来更新进度条.第一种不适合在更新频率比較高的地方,比方一秒钟发送了20个事件,这样会造成主线程忙于处理事件界面出现假死状态. 所以最好的办法就是使用第2种通过定时器更新进度条,设置一个合理的

[C/C++标准库]_[0基础]_[使用fstream合并文本文件]

场景: 1. 就是合并文本文件,而且从第2个文件起不要合并第一行. 2. 多加了一个功能,就是支持2个以上的文件合并. 3. 问题: http://ask.csdn.net/questions/192151 仅仅能说非常easy: 基础只是关吧,这位同学,也有可能不是开发的,放这里也是为了培训基础差的. test.cpp #include <fstream> #include <string> #include <iostream> using namespace st

[网络]_[0基础]_[使用putty备份远程数据]

场景: 1. putty是windows上訪问linux服务的免费client之中的一个.用它来ssh到远程server备份数据是常见的做法(在没做好自己主动备份机制前), 通过putty界面尽管也不难.可是每次 反复性的工作总是非常烦人,这时候能够使用putty的命令行工具+批处理写一个自己主动备份下载工具. 写一个批处理文件: backup.bat @echo off @echo 開始备份数据 putty\plink.exe -ssh -l 帐号名 -pw password 192.168.

[zlib]_[0基础]_[使用Zlib完整解压zip内容]

场景: 1. 解压文件一般用在下载了一个zip文件之后解压,或者分析某个文件须要解压的操作上. 2. 解压文件,特别是解压带目录的zip文件往往系统没有提供这类Win32 API,当然C#自带库能解压, 当然这里仅仅讨论C/C++, 像C#和Java这样的开挂的标准库不在考虑范围内. 3. zlib解压文件的使用样例在 contrib\minizip 样例里. 这里基本是直接提取miniunz.c 的代码进行封装解压就可以, 仅仅是改了下支持中文路径. 主文件 zip_util.cpp #inc

[C/C++11语法]_[0基础]_[lamba 表达式介绍]

场景 lambda 表达式在非常多语言里都有一席之地,由于它的原因,能够在函数里高速定义一个便携的函数,或者在函数參数里直接高速构造和传递. 它能够说是匿名函数对象,一般仅仅适用于某个函数内,仅仅做暂时使用. 通常是须要在对某个数据暂时特殊处理时使用,比方对某种參数类型进行限定的再次封装和行为约束. 參考 1. C# Lambda表达式及其优势 2. Lambda Expressions in C++ 3. Exception Specifications (throw) (C++) 4. no

[ATL/WTL]_[0基础]_[CBitmap复制图片-截取图片-平铺图片]

场景: 1.当你须要截取图片部分区域作为某个控件的背景. 2.须要平铺图片到一个大区域让他自己主动放大时. 3.或者须要合并图片时. 代码: CDC sdc; CDC ddc; sdc.CreateCompatibleDC(NULL); ddc.CreateCompatibleDC(NULL); CBitmap destBmp; destBmp.CreateCompatibleBitmap(CClientDC(NULL),width,height); sdc.SelectBitmap(m_Bit

[C/C++标准库]_[0基础]_[优先队列priority_queue的使用]

std::priority_queue 场景: 1. 对于一个任务队列,任务的优先级由任务的priority属性指明,这时候就须要优先级越高的先运行.而queue并没有排序功能,这时priority_queue是比較好的选择. 2 对于异步的task也是一样.在不断加入新的task时,当然希望优先级越高的先运行. 解析: 1. 假设须要把优先级最高的先pop,那么comp比較时须要返回false. 代码: //1.Elements are popped from the "back"

[C/C++]_[0基础]_[static_cast,reinterpret_cast,dynimic_cast的使用场景和差别]

场景: 1. C++的对象差别于C的原因是他们能够有继承关系, 方法有重载, 覆盖关系等, 他们的对象内存数据结构因此也比較复杂. 2. 非常多情况下我们须要一个父类来存储子类的指针对象进行通用方法的操作.涉及到详细某个子类对象特定操作时又须要强制转换为子类.那么这时候该用什么好呢? 答: 假设不须要类型检查的话就直接用C的强制转换就可以(B*)c. 可是C++ 之父并不推荐使用C的强制类型转换; 原因1是没有编译器检查. 原因2是对象指针在子类父类之间转换时所相应的地址值可能会变化, 这样用C

[wxWidgets]_[0基础]_[不常见但有用的类wxCmdLineParser]

场景: 1. 有时候须要构造命令行字符串传递給函数调用,比方CreateProcess,假设參数是动态的,那么就得使用类似std::vector<string>加入单个參数,之后拼接为一个string. wx有给这类处理类.就是wxCmdLineParser ,它既能拼接为字符串.又能够把字符串分解为一个參数数组. console.cpp #include "wx/wxprec.h" #ifndef WX_PRECOMP #include "wx/wx.h&quo