Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++11 Libcurl+;流式反序列化的rapidjson?_C++11_Stream_Libcurl_Sax_Rapidjson - Fatal编程技术网

C++11 Libcurl+;流式反序列化的rapidjson?

C++11 Libcurl+;流式反序列化的rapidjson?,c++11,stream,libcurl,sax,rapidjson,C++11,Stream,Libcurl,Sax,Rapidjson,我一直在绞尽脑汁(虽然一开始并不多),试图找到一种方法来点击一个web服务,然后分块解析和反序列化json,同时解析到我的对象中,而不存储整个文档(500mb+)。实际上,我正试图使用SAX风格的解析将libcurl和rapidjson直接连接到我的类中 也许我认为这是错误的,但我目前的想法是,在curl_写回期间,将接收到的数据添加到json文本流中。我正在努力解决的是如何启动rapidjson解析引擎,然后让它等待下一个数据块从curl写回中进入。在处理未完成的令牌之前停止,直到接收到新的流

我一直在绞尽脑汁(虽然一开始并不多),试图找到一种方法来点击一个web服务,然后分块解析和反序列化json,同时解析到我的对象中,而不存储整个文档(500mb+)。实际上,我正试图使用SAX风格的解析将libcurl和rapidjson直接连接到我的类中

也许我认为这是错误的,但我目前的想法是,在curl_写回期间,将接收到的数据添加到json文本流中。我正在努力解决的是如何启动rapidjson解析引擎,然后让它等待下一个数据块从curl写回中进入。在处理未完成的令牌之前停止,直到接收到新的流缓冲区。我不想附加缓冲区,因为我想释放上一个缓冲区

以前有人这样做过吗

这里有一些代码来说明这个概念…但显然不完整(可能都错了!)

下面是将信息传递给curl_write的结构,以便它知道如何回调解析器

struct CurlHandler {
    stringstream *data;
    Reader *reader;
    void *parsehandler;
};
然后在启动请求之前,我按如下方式填充结构:

rapidjson::Reader reader;
CurlHandler handler;
ParseHandler parser;
handler.reader = &reader;
handler.parsehandler = &parser;
SetOption(CURLOPT_WRITEDATA, (void *) &handler);
ParseHandler是rapidjson进行SAX解析所需的类。其想法是在curl_编写过程中调用rapidjson解析器(不知何故):

static size_t curl_write(void *ptr, size_t size, size_t nmemb, void *CurlHandlerPtr) {
    CurlHandler *handler = (CurlHandler *) CurlHandlerPtr;

//  handler->reader.Parse(handler->data, handler->parsehandler);   ????????

    return 1;
}
我当然希望有比这更简单的答案

以下是上下文的完整代码:

#pragma once
#include <string>
#include <iostream>
#include "curl\curl.h"
#include "rapidjson\rapidjson.h"
#include "rapidjson\reader.h"

using namespace std;
using namespace rapidjson;

struct CurlHandler {
    stringstream *data;
    Reader *reader;
    void *parsehandler;
};

static size_t curl_write(void *ptr, size_t size, size_t nmemb, void *CurlHandlerPtr) {
    CurlHandler *handler = (CurlHandler *) CurlHandlerPtr;

//  handler->reader.Parse(handler->data, handler->parsehandler);   ????????

    return 1;
}


class ParseHandler {
    bool Null() { cout << "Null()" << endl; return true; }
    bool Bool(bool b) { cout << "Bool(" << boolalpha << b << ")" << endl; return true; }
    bool Int(int i) { cout << "Int(" << i << ")" << endl; return true; }
    bool Uint(unsigned u) { cout << "Uint(" << u << ")" << endl; return true; }
    bool Int64(int64_t i) { cout << "Int64(" << i << ")" << endl; return true; }
    bool Uint64(uint64_t u) { cout << "Uint64(" << u << ")" << endl; return true; }
    bool Double(double d) { cout << "Double(" << d << ")" << endl; return true; }
    bool String(const char* str, SizeType length, bool copy) {
        cout << "String(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
        return true;
    }
    bool StartObject() { cout << "StartObject()" << endl; return true; }
    bool Key(const char* str, SizeType length, bool copy) {
        cout << "Key(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
        return true;
    }
    bool EndObject(SizeType memberCount) { cout << "EndObject(" << memberCount << ")" << endl; return true; }
    bool StartArray() { cout << "StartArray()" << endl; return true; }
    bool EndArray(SizeType elementCount) { cout << "EndArray(" << elementCount << ")" << endl; return true; }
};

class StreamTest {
private:
    string _username;
    string _password;

    CURL *_curl;
    CURLcode _error;

public:
    StreamTest() {
        curl_global_init(CURL_GLOBAL_ALL);
        _curl = curl_easy_init();
    };
    ~StreamTest() {
        curl_global_cleanup();
    };

    int Initialize(string username, string password) {
        _username = username;
        _password = password;
        return 0;
    }

    int Get(std::string url) {
        CURLcode result;

        rapidjson::Reader reader;
        CurlHandler handler;
        ParseHandler parser;
        handler.reader = &reader;
        handler.parsehandler = &parser;

        std::string s = _username; s += ":"; s += _password;

        SetOption(CURLOPT_USERPWD, s.c_str());
        SetOption(CURLOPT_URL, url.c_str());
        SetOption(CURLOPT_WRITEFUNCTION, curl_write);
        SetOption(CURLOPT_WRITEDATA, (void *) &handler);
        result = curl_easy_perform(_curl);

        return 0;
    }

    template <typename ValueType>
    StreamTest& SetOption(CURLoption opt, ValueType val) {
        if(_curl && _error == CURLE_OK) {
            _error = curl_easy_setopt(_curl, opt, val);
        }
        return *this;
    }
};

int _tmain(int argc, _TCHAR* argv[]) {
    StreamTest http;

    http.Initialize("guest", "passwd");

    http.Get("http://localhost/GetData");

    cin.get();
}
#pragma一次
#包括
#包括
#包括“curl\curl.h”
#包括“rapidjson\rapidjson.h”
#包括“rapidjson\reader.h”
使用名称空间std;
使用名称空间rapidjson;
结构卷曲处理程序{
stringstream*数据;
读取器*读取器;
void*parsehandler;
};
静态大小卷曲写入(void*ptr、size\t size、size\t nmemb、void*CurlHandlerPtr){
CurlHandler*handler=(CurlHandler*)CurlHandlerPtr;
//handler->reader.Parse(handler->data,handler->parsehandler)????????
返回1;
}
类分析器处理程序{

bool Null(){coutRapidJSON的设计本身不支持解析期间的暂停/恢复。因为这将为备份/恢复解析状态增加大量开销

然而,上述需求可以通过使用Libcurl来解决,它实际上使用多线程

libcurl中的一个示例演示了如何将HTTP GET模拟为标准文件I/O API。使用此示例可以方便地修改
rapidjson::FileReadStream
,以支持从HTTP解析JSON


一般来说,开发人员在使用RapidJSON时可能会使用多线程来解决此类问题。

这是一个概念:创建一个具有读写端的匿名管道。在传递给
WRITEFUNCTION
的回调中,将从curl接收的字节写入管道的写端。然后在另一个线程中,而不是传递
rapidjson::StringStream
对象到
reader.Parse()
,传递一个从管道读取端创建的
rapidjson::FileReadStream
对象。当回调写入管道时,SAX读取器读取并解析管道中的数据。

Milo,谢谢,但解析速度不是问题,所以我不确定是否需要多线程。rapidjson非常快。问题是primar减少内存消耗。如果我所做的只是将只读解析转发到一个对象中,我宁愿不将500MB+的文件加载到内存中。我认为在我的回答中使用这种方法也可以减少内存。只要使用SAX接口和从HTTP流式传输JSON,就不需要将整个JSON存储在内存中。Libcurl的多接口不需要se线程。它使用文件描述符等待传输,从而最小化等待时间。与串行传输链相反。文件描述符在系统级别上运行。