C++ 可以处理大输入(2GB)的JSON解析器?
到目前为止,我已经尝试过(没有成功):C++ 可以处理大输入(2GB)的JSON解析器?,c++,c,json,C++,C,Json,到目前为止,我已经尝试过(没有成功): –“文档太大”(看起来最大大小被人为地限制在1签出。我用一个大型数据库(SF street data或其他,大约2GB)对其进行了测试。速度相当快。签出。我用一个大型数据库(SF street data或其他,大约2GB)对其进行了测试。速度相当快。好吧,我对我的解决方案并不感到自豪,但我最终使用了一些正则表达式将数据拆分为顶级键值对(每个键值对只有几MB),然后用Qt的JSON解析器解析其中的每一对,并将它们传递到我的原始代码中 Yajl正是我所需要的
- –“文档太大”(看起来最大大小被人为地限制在
1签出。我用一个大型数据库(SF street data或其他,大约2GB)对其进行了测试。速度相当快。签出。我用一个大型数据库(SF street data或其他,大约2GB)对其进行了测试。速度相当快。好吧,我对我的解决方案并不感到自豪,但我最终使用了一些正则表达式将数据拆分为顶级键值对(每个键值对只有几MB),然后用Qt的JSON解析器解析其中的每一对,并将它们传递到我的原始代码中 Yajl正是我所需要的,但我选择了丑陋的正则表达式,因为:
- 将我的逻辑融入其中需要重写足够多的代码,这是一件痛苦的事情,而这只是为了一个一次性的MapReduce工作,因此代码本身对长期来说并不重要
- 数据集由我控制,并保证始终与我的正则表达式一起工作
- 出于各种原因,向弹性MapReduce部署中添加依赖项比它应该做的要麻烦得多(并且静态Qt编译有缺陷),因此为了不做超出必要的工作,我倾向于将依赖项保持在最低限度
- 这仍然有效,并且性能良好(时间和内存方面)
请注意,我使用的正则表达式恰好适用于我的数据,因为顶级键(只有顶级键)是整数;我下面的代码不是一个通用的解决方案,我不会建议在SAX风格的解析器上使用类似的方法,因为上面的原因1和2不适用 还要注意的是,这个解决方案是额外的(在解析之前拆分和操作JSON字符串+数据开始和结束的特殊情况),因为捕获整个键值对的原始表达式在其中一个键值对超过(在这种情况下,这甚至是一件事,这令人难以置信地恼火,特别是因为它不能通过QRegularExpression或grep进行配置)
不管怎样,代码是这样的;我深感惭愧:QFile file( argv[1] ); file.open( QIODevice::ReadOnly ); QTextStream textStream( &file ); QString jsonKey; QString jsonString; QRegularExpression jsonRegex( "\"-?\\d+\":" ); bool atEnd = false; while( atEnd == false ) { QString regexMatch = jsonRegex.match ( jsonString.append( textStream.read(1000000) ) ).captured(); bool isRegexMatched = regexMatch.isEmpty() == false; if( isRegexMatched == false ) { atEnd = textStream.atEnd(); } if( atEnd || (jsonKey.isEmpty() == false && isRegexMatched) ) { QString jsonObjectString; if( atEnd == false ) { QStringList regexMatchSplit = jsonString.split( regexMatch ); jsonObjectString = regexMatchSplit[0] .prepend( jsonKey ) .prepend( LEFT_BRACE ) ; jsonObjectString = jsonObjectString .left( jsonObjectString.size() - 1 ) .append( RIGHT_BRACE ) ; jsonKey = regexMatch; jsonString = regexMatchSplit[1]; } else { jsonObjectString = jsonString .prepend( jsonKey ) .prepend( LEFT_BRACE ) ; } QJsonObject jsonObject = QJsonDocument::fromJson ( jsonObjectString.toUtf8() ).object(); QString key = jsonObject.keys()[0]; ... process data and store in boost::interprocess::map ... } else if( isRegexMatched ) { jsonKey = regexMatch; jsonString = jsonString.split( regexMatch )[1]; } }
好吧,我对我的解决方案并不感到自豪,但我最终使用一些正则表达式将我的数据拆分为顶级键值对(每个键值对只有几MB),然后用Qt的JSON解析器解析这些键值对中的每一个,并将它们传递到我的原始代码中 Yajl正是我所需要的,但我选择了丑陋的正则表达式,因为:- 将我的逻辑融入其中需要重写足够多的代码,这是一件痛苦的事情,而这只是为了一个一次性的MapReduce工作,因此代码本身对长期来说并不重要
- 数据集由我控制,并保证始终与我的正则表达式一起工作
- 出于各种原因,向弹性MapReduce部署中添加依赖项比它应该做的要麻烦得多(并且静态Qt编译有缺陷),因此为了不做超出必要的工作,我倾向于将依赖项保持在最低限度
- 这仍然有效,并且性能良好(时间和内存方面)
请注意,我使用的正则表达式恰好适用于我的数据,因为顶级键(只有顶级键)是整数;我下面的代码不是一个通用的解决方案,我不会建议在SAX风格的解析器上使用类似的方法,因为上面的原因1和2不适用 还要注意的是,这个解决方案是额外的(在解析之前拆分和操作JSON字符串+数据开始和结束的特殊情况),因为捕获整个键值对的原始表达式在其中一个键值对超过(在这种情况下,这甚至是一件事,这令人难以置信地恼火,特别是因为它不能通过QRegularExpression或grep进行配置)
不管怎样,代码是这样的;我深感惭愧:
我最近完成了这样一个库(可能还有一点测试版):QFile file( argv[1] ); file.open( QIODevice::ReadOnly ); QTextStream textStream( &file ); QString jsonKey; QString jsonString; QRegularExpression jsonRegex( "\"-?\\d+\":" ); bool atEnd = false; while( atEnd == false ) { QString regexMatch = jsonRegex.match ( jsonString.append( textStream.read(1000000) ) ).captured(); bool isRegexMatched = regexMatch.isEmpty() == false; if( isRegexMatched == false ) { atEnd = textStream.atEnd(); } if( atEnd || (jsonKey.isEmpty() == false && isRegexMatched) ) { QString jsonObjectString; if( atEnd == false ) { QStringList regexMatchSplit = jsonString.split( regexMatch ); jsonObjectString = regexMatchSplit[0] .prepend( jsonKey ) .prepend( LEFT_BRACE ) ; jsonObjectString = jsonObjectString .left( jsonObjectString.size() - 1 ) .append( RIGHT_BRACE ) ; jsonKey = regexMatch; jsonString = regexMatchSplit[1]; } else { jsonObjectString = jsonString .prepend( jsonKey ) .prepend( LEFT_BRACE ) ; } QJsonObject jsonObject = QJsonDocument::fromJson ( jsonObjectString.toUtf8() ).object(); QString key = jsonObject.keys()[0]; ... process data and store in boost::interprocess::map ... } else if( isRegexMatched ) { jsonKey = regexMatch; jsonString = jsonString.split( regexMatch )[1]; } }
如果您使用json_类,它会将所有内容加载到内存中,这可能不是您想要的 但是您可以通过编写自己的“映射器”来按顺序解析它 包含的映射器迭代JSON,将输入映射到JSON类:https://github.com/matiu2/json--11
您可以编写自己的,对数据做任何您想做的事情,并向其中提供一个文件流,这样就不会将整批数据加载到内存中 因此,作为一个开始的示例,这只是以某种随机格式输出json数据,但不会填充任何内存(完全未测试或编译):https://github.com/matiu2/json--11/blob/master/src/mapper.hpp
#包括“parser.hpp” #包括 #包括 #包括 int main(int argc,char**){ std::ifstream文件(“hugeJSONFile.hpp”); std::istream_迭代器输入(文件); 自动解析器=json::解析器(输入); 使用Parser=decltype(解析器); 使用std::cout; 使用std::endl; 开关(parser.getNextType()){ 大小写分析器::null: parser.readNull(); cout我最近完成了这样一个库(可能还有点测试版):
如果您使用json_类,它会将所有内容加载到内存中,这可能不是您想要的 但是您可以通过编写自己的“映射器”来按顺序解析它 包含的映射器迭代JSON,将输入映射到JSON类:https://github.com/matiu2/json--11
您可以编写自己的,对数据做任何您想做的事情,并向其中提供一个文件流,这样就不会将整批数据加载到内存中 因此,作为一个开始的示例,这只是以某种随机格式输出json数据,但不会填充任何内存(完全未测试或编译):https://github.com/matiu2/json--11/blob/master/src/mapper.hpp
#包括“parser.hpp” #包括 #包括 #包括 int main(int argc,char**){ std::ifstream文件(“hugeJSONFile.hpp”); std::istream_迭代器输入(文件); 自动解析器=json::解析器(输入); 使用Parser=decltype(pars