C++使用libcurl轻松实现文件下载

 更新时间:2025年08月21日 08:34:44   作者:xiaokang-coding  
这篇文章将用最简单的方式,带大家掌握C++ + libcurl实现文件下载的核心技术,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下

最近很多同学在后台问我:"康哥,想用C++实现文件下载功能,但不知道从哪里入手,网上的教程要么太简单,要么太复杂,有没有适合新手的实战教程?"

今天就来满足大家的需求!用最简单的方式,带你掌握C++ + libcurl实现文件下载的核心技术。

不仅让你学会基础下载,更重要的是为后续的多线程高性能下载器打下坚实基础!

为什么选择libcurl?

在C++中实现HTTP下载,我们有很多选择:

  • socket编程:太底层,需要手动处理HTTP协议
  • 第三方网络库:学习成本高,依赖复杂
  • libcurl:工业级标准,简单易用,几乎所有Linux系统都预装

libcurl的优势:

  • 久经考验: 被Git用于HTTP操作,被PHP内置cURL扩展采用
  • 功能强大:支持HTTP/HTTPS/FTP等20+协议
  • 文档完善:官方文档详细,社区活跃
  • 性能优秀:C语言实现,效率极高
  • 跨平台:Windows/Linux/macOS全支持

环境准备

Ubuntu/Debian系统

sudo apt-get update
sudo apt-get install libcurl4-openssl-dev

CentOS/RHEL系统

sudo yum install libcurl-devel
# 或者新版本使用
sudo dnf install libcurl-devel

验证安装

curl-config --version

如果显示版本号,说明安装成功!

第一个下载程序:HelloDownloader

我们从最简单的例子开始。创建文件 hello_downloader.cpp

#include <iostream>
#include <fstream>
#include <curl/curl.h>

// 数据写入回调函数
size_t writeData(void* ptr, size_t size, size_t nmemb, FILE* stream) {
    size_t written = fwrite(ptr, size, nmemb, stream);
    return written;
}

int main() {
    CURL* curl;
    FILE* fp;
    CURLcode res;
    
    // 下载链接(这是一个测试文件)
    const char* url = "https://httpbin.org/json";
    const char* outfilename = "test.json";
    
    // 全局初始化curl
    curl_global_init(CURL_GLOBAL_DEFAULT);
    
    // 创建curl句柄
    curl = curl_easy_init();
    if(curl) {
        // 打开本地文件准备写入
        fp = fopen(outfilename, "wb");
        if(!fp) {
            std::cerr << "无法创建文件!" << std::endl;
            curl_easy_cleanup(curl);
            curl_global_cleanup();
            return 1;
        }
        
        // 设置URL
        curl_easy_setopt(curl, CURLOPT_URL, url);
        
        // 设置写入回调函数
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeData);
        
        // 设置写入文件指针
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
        
        // 跟随重定向
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        
        // 执行下载
        res = curl_easy_perform(curl);
        
        // 检查结果
        if(res != CURLE_OK) {
            std::cerr << "下载失败: " << curl_easy_strerror(res) << std::endl;
        } else {
            std::cout << "下载成功!文件保存为: " << outfilename << std::endl;
        }
        
        // 清理
        fclose(fp);
        curl_easy_cleanup(curl);
    }
    
    curl_global_cleanup();
    return 0;
}

编译运行:

g++ -o hello_downloader hello_downloader.cpp -lcurl
./hello_downloader

如果一切正常,你会看到:

下载成功!文件保存为: test.json

恭喜!你的第一个C++下载器诞生了!

进阶版本:带进度显示的下载器

基础版本太朴素?来个炫酷的进度条版本!

#include <iostream>
#include <fstream>
#include <iomanip>
#include <curl/curl.h>

// 进度回调函数
int progressCallback(void* ptr, double totalToDownload, double nowDownloaded, 
                    double totalToUpload, double nowUploaded) {
    if (totalToDownload <= 0.0) return 0;
    
    double percentage = (nowDownloaded / totalToDownload) * 100.0;
    int barWidth = 50;
    int pos = static_cast<int>(barWidth * percentage / 100.0);
    
    std::cout << "\r[";
    for (int i = 0; i < barWidth; ++i) {
        if (i < pos) std::cout << "=";
        else if (i == pos) std::cout << ">";
        else std::cout << " ";
    }
    std::cout << "] " << std::fixed << std::setprecision(1) << percentage << "%";
    std::cout << " (" << static_cast<long>(nowDownloaded) << "/" 
              << static_cast<long>(totalToDownload) << " bytes)";
    std::cout.flush();
    
    return 0;
}

// 写入数据回调
size_t writeData(void* ptr, size_t size, size_t nmemb, FILE* stream) {
    return fwrite(ptr, size, nmemb, stream);
}

class SimpleDownloader {
private:
    CURL* curl;
    
public:
    SimpleDownloader() {
        curl_global_init(CURL_GLOBAL_DEFAULT);
        curl = curl_easy_init();
    }
    
    ~SimpleDownloader() {
        if (curl) {
            curl_easy_cleanup(curl);
        }
        curl_global_cleanup();
    }
    
    bool download(const std::string& url, const std::string& filename) {
        if (!curl) return false;
        
        FILE* fp = fopen(filename.c_str(), "wb");
        if (!fp) {
            std::cerr << "无法创建文件: " << filename << std::endl;
            return false;
        }
        
        // 基本设置
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeData);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        
        // 进度显示设置
        curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
        curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progressCallback);
        
        // 用户代理(有些网站需要)
        curl_easy_setopt(curl, CURLOPT_USERAGENT, "SimpleDownloader/1.0");
        
        // 超时设置
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 300L);  // 5分钟超时
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30L);  // 连接30秒超时
        
        std::cout << "开始下载: " << url << std::endl;
        CURLcode res = curl_easy_perform(curl);
        std::cout << std::endl;  // 换行
        
        fclose(fp);
        
        if (res != CURLE_OK) {
            std::cerr << "下载失败: " << curl_easy_strerror(res) << std::endl;
            return false;
        }
        
        std::cout << "下载完成!文件保存为: " << filename << std::endl;
        return true;
    }
};

int main() {
    SimpleDownloader downloader;
    
    // 你可以替换成任何你想下载的文件
    std::string url = "https://httpbin.org/json";
    std::string filename = "downloaded_file.json";
    
    if (downloader.download(url, filename)) {
        std::cout << "下载成功!" << std::endl;
    } else {
        std::cout << "下载失败!" << std::endl;
    }
    
    return 0;
}

编译运行:

g++ -o progress_downloader progress_downloader.cpp -lcurl
./progress_downloader

你会看到类似这样的效果:

开始下载: https://httpbin.org/json
[==================================================] 100.0% (429/429 bytes)

核心概念详解

1. CURL句柄管理

// 全局初始化(程序启动时调用一次)
curl_global_init(CURL_GLOBAL_DEFAULT);

// 创建会话句柄
CURL* curl = curl_easy_init();

// 使用完毕后清理
curl_easy_cleanup(curl);
curl_global_cleanup();

2. 关键选项设置

// 基础设置
curl_easy_setopt(curl, CURLOPT_URL, url);                    // 设置URL
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);          // 跟随重定向
curl_easy_setopt(curl, CURLOPT_USERAGENT, "MyApp/1.0");      // 用户代理

// 超时控制
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 300L);               // 总超时时间
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30L);         // 连接超时

// SSL设置(HTTPS需要)
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);          // 验证证书
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);          // 验证主机名

3. 回调函数机制

libcurl通过回调函数处理数据:

// 数据接收回调
size_t writeCallback(void* contents, size_t size, size_t nmemb, void* userp) {
    size_t realsize = size * nmemb;
    // 处理接收到的数据
    return realsize;  // 返回处理的字节数
}

// 进度回调
int progressCallback(void* clientp, double dltotal, double dlnow, 
                    double ultotal, double ulnow) {
    // 显示进度信息
    return 0;  // 返回0继续,非0中止
}

常见问题与解决方案

问题1:编译时找不到curl.h

解决方案:

# 检查是否安装开发包
dpkg -l | grep curl
# 如果没有,重新安装
sudo apt-get install libcurl4-openssl-dev

问题2:下载HTTPS链接失败

解决方案:

// 添加SSL设置
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
curl_easy_setopt(curl, CURLOPT_CAINFO, "/etc/ssl/certs/ca-certificates.crt");

问题3:某些网站返回403错误

解决方案:

// 设置更真实的用户代理
curl_easy_setopt(curl, CURLOPT_USERAGENT, 
    "Mozilla/5.0 (Linux; x86_64) AppleWebKit/537.36");

// 添加请求头
struct curl_slist* headers = NULL;
headers = curl_slist_append(headers, "Accept: */*");
headers = curl_slist_append(headers, "Accept-Encoding: gzip, deflate");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

性能优化小贴士

1. 启用压缩

curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "");  // 自动处理所有支持的编码

2. 复用连接

curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);
curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);

3. 设置合适的缓冲区

curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, 102400L);  // 100KB缓冲区

总结

通过这篇教程,我们学会了:

  • libcurl环境搭建:快速安装和配置
  • 基础下载实现:从最简单的 demo 开始
  • 进阶功能添加:进度显示、错误处理、超时控制
  • 面向对象封装:用类封装提高代码复用性
  • 常见问题解决:实际开发中的坑点和解决方案

现在你已经掌握了C++单线程下载的核心技术!

但是,单线程下载在面对大文件时还是太慢了。试想一下:

  • 下载几GB的文件需要等很久
  • 网络中断后又要重新开始
  • ....

如果能实现多线程并发下载,速度提升10倍以上,那该多爽!

到此这篇关于C++使用libcurl轻松实现文件下载的文章就介绍到这了,更多相关C++ libcurl文件下载内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 老程序员教你一天时间完成C++俄罗斯方块游戏

    老程序员教你一天时间完成C++俄罗斯方块游戏

    俄罗斯方块游戏大家应该非常熟悉,非常经典的一款游戏,本文来详细讲解下俄罗斯方块游戏的制作过程,赶紧来看下吧!希望能给你带来帮助
    2021-08-08
  • C++实现简单通讯录管理系统

    C++实现简单通讯录管理系统

    这篇文章主要为大家详细介绍了C++实现简单通讯录管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • 一文详解C++17中的结构化绑定

    一文详解C++17中的结构化绑定

    C++17中的结构化绑定(structured binding)是指将指定名称绑定到初始化程序的子对象或元素,本文主要来和大家聊聊C++17中结构化绑定的实现,感兴趣的小伙伴可以了解下
    2023-12-12
  • 一文详解C语言操作符

    一文详解C语言操作符

    这篇文章主要详细介绍了C语言的操作符,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • C++设计模式之迭代器模式

    C++设计模式之迭代器模式

    这篇文章主要介绍了C++设计模式之迭代器模式,本文讲解了什么是迭代器模式、迭代器模式的代码实例等内容,需要的朋友可以参考下
    2014-10-10
  • C++ 读文件 将文件内容读入到字符串string中的方法

    C++ 读文件 将文件内容读入到字符串string中的方法

    今天小编就为大家分享一篇C++ 读文件 将文件内容读入到字符串string中的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-07-07
  • C++使用opencv读取图片的操作代码(图像处理)

    C++使用opencv读取图片的操作代码(图像处理)

    这篇文章主要介绍了C++使用opencv读取图片,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04
  • 一起来学习C语言的程序环境与预处理

    一起来学习C语言的程序环境与预处理

    这篇文章主要为大家详细介绍了C语言程序环境与预处理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • C/C++中使用局部/全局变量初始值或默认值问题

    C/C++中使用局部/全局变量初始值或默认值问题

    这篇文章主要介绍了C/C++中使用局部/全局变量初始值或默认值问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • C语言中关于库函数 qsort 快排的用法

    C语言中关于库函数 qsort 快排的用法

    快速排序Qsort是所有学习算法和数据结构最基础的一个部分,也是考试题和面试的一个小重点。本片文章带你了解Qsort的详细用法规则
    2021-09-09

最新评论