curlopt_writefunction必须配对使用curlopt_writedata,否则回调函数接收野指针导致崩溃;回调需严格符合签名并返回sizenmemb;文件写入应直接用file零拷贝,注意windows中文路径需转宽字符。

curl_easy_setopt 里 CURLOPT_WRITEFUNCTION 必须配对用 CURLOPT_WRITEDATA
不设 CURLOPT_WRITEDATA,自定义写回调函数就收不到有效指针,文件内容会写到野指针或直接崩溃。常见错误是只写回调但忘了传 FILE* 或缓冲区地址。
-
CURLOPT_WRITEFUNCTION告诉 libcurl “用这个函数写数据”,但它不负责管理内存或文件句柄 -
CURLOPT_WRITEDATA才是真正传进去的上下文,比如fopen("out.bin", "wb")返回的FILE* - 回调函数签名必须严格为
size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata),否则 ABI 不匹配,运行时可能段错误 - 返回值要等于
size * nmemb,否则 libcurl 认为写失败,中止下载
用 FILE* 直接写比内存缓冲再落盘更稳
新手常想先 std::vector<char></char> 接收全部数据再 fwrite,但大文件容易爆内存,且没进度反馈。直接对接 FILE* 是 libcurl 原生支持的零拷贝路径。
- 打开文件用
"wb"模式(Windows 下尤其注意,缺b会导致换行符错乱) - 回调里直接调
fwrite(ptr, 1, size * nmemb, (FILE*)userdata),不用自己算偏移 - 下载中途出错时,
FILE*已写入部分仍保留,可做断点续传基础(只要服务端支持Range) - 别忘了下载完
fclose(),否则文件可能没刷盘、资源泄漏
HTTP 状态码 200 不代表文件完整,得检查 curl_easy_perform 返回值
curl_easy_perform 返回 CURLE_OK 才算传输完成;如果网络断了、DNS 失败、SSL 验证失败,即使 HTTP 响应头已收到,也会返回非零值,此时文件可能为空或截断。
- 不要只看
CURLOPT_HEADERFUNCTION是否收到HTTP/1.1 200,那是 header 解析阶段的事 - 务必检查
curl_easy_perform返回值,CURLE_PARTIAL_FILE表示服务器声称发了 10MB 但只收到 2MB - 配合
CURLOPT_FAILONERROR设为 1L,能让 4xx/5xx 响应直接让curl_easy_perform失败,省去手动解析状态码 - 超时要用
CURLOPT_TIMEOUT(总耗时)和CURLOPT_CONNECTTIMEOUT(建连),别只靠系统默认
Windows 下 fopen 路径含中文会失败,得转 UTF-8 或用 _wfopen
libcurl 内部全用 UTF-8 处理 URL 和路径,但 Windows 的 fopen 默认用本地 ANSI 编码(如 GBK)。路径含中文时,fopen("测试.txt", "wb") 实际打开的是乱码文件名,甚至失败返回 NULL。
- 最简方案:把路径转成 UTF-8 字节流,再用
_wfopen(需#include <stdio.h></stdio.h>和#include <wchar.h></wchar.h>) - 转宽字符示例:
std::wstring wpath = std::filesystem::u8path(u8"中文目录/文件.zip").wstring();,然后_wfopen(wpath.c_str(), L"wb") - Linux/macOS 无此问题,
fopen原生接受 UTF-8 路径 - 别用
CURLOPT_UPLOAD或CURLOPT_READFUNCTION来绕开——那是上传逻辑,和下载保存无关
实际跑通的关键不在 callback 写得多漂亮,而在 CURLOPT_WRITEDATA 有没有传对、curl_easy_perform 的返回值有没有真看、Windows 路径有没有躲过编码坑。这三个点漏一个,程序就静默出错。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











