如何在C++中将curl获取的数据读取到std::stringstream中?
问题:如何让libcurl直接写入std::stringstream并通过getline处理数据
我在处理Web API,需要读取文本数据做后续处理,数据量最高可达90MB。想把数据直接读到std::stringstream里,之后用std::getline()逐行存入std::string,但没法让curl和stringstream配合工作。
我的代码如下:
#include <iostream> #include <sstream> #include <string> #include <curl/curl.h> static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; std::stringstream *stream=(std::stringstream *)userp; return realsize; } int main(int argc, char* argv[]) { CURL *curl; CURLcode res; std::stringstream stream; curl = curl_easy_init(); if (curl) { curl_easy_setopt(curl, CURLOPT_URL, "http://date.jsontest.com/"); // simple, small example curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&stream); res = curl_easy_perform(curl); curl_easy_cleanup(curl); } std::cout << "[" << stream.str() << "]" << std::endl; // the loop with getline() would enter here return 0; }
输出结果:
[]
我尝试过这些方法但没解决:
- 参考过用istream的代码,但编译报错
basic_istream is protected within this context - 试过在回调里替换成istream,也去掉过(void*)强制转换,但stream始终为空
- 知道可以用std::string替代,但觉得用getline拆分比自己处理字符串更快;也试过先读入string再转stream,但会复制整个字符串,效率低
编辑补充:常见的curl写入string的回调代码是这样的:
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) { ((std::string*)userp)->append((char*)contents, size * nmemb); return size * nmemb; }
我意识到自己的回调和这个差距很大,但不知道怎么向stringstream追加数据。
解决方法
核心问题是你的WriteMemoryCallback根本没把curl返回的内容写入stringstream,只计算了字节数就返回了。要实现直接写入,调用std::stringstream::write()方法即可,它能直接接收字符指针和字节数,把数据追加到流中。
修改后的回调函数
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; // 用static_cast替代C风格强制转换,更符合C++规范 std::stringstream *stream = static_cast<std::stringstream*>(userp); // 将curl传来的内容写入stringstream stream->write(static_cast<char*>(contents), realsize); return realsize; }
完整可运行代码
#include <iostream> #include <sstream> #include <string> #include <curl/curl.h> static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; std::stringstream *stream = static_cast<std::stringstream*>(userp); stream->write(static_cast<char*>(contents), realsize); return realsize; } int main(int argc, char* argv[]) { CURL *curl; CURLcode res; std::stringstream stream; curl = curl_easy_init(); if (curl) { curl_easy_setopt(curl, CURLOPT_URL, "http://date.jsontest.com/"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &stream); res = curl_easy_perform(curl); curl_easy_cleanup(curl); } // 用getline逐行读取流中数据 std::string line; while (std::getline(stream, line)) { std::cout << "读取到行:" << line << std::endl; } return 0; }
关键说明
std::stringstream::write()直接操作流的内部缓冲区,不需要额外复制数据(除非缓冲区扩容,这是流的正常机制,和写入std::string的开销一致)- 避免了先写入string再转流的二次复制,符合你对效率的要求
- 回调必须返回实际处理的字节数,curl会根据这个判断传输是否正常,如果返回值和
realsize不一致,curl会中断传输
内容的提问来源于stack exchange,提问作者Rodrigo
相关产品推荐
相关产品推荐

