1.问题
rapidjson性能非常棒,在处理大数据量的情况下性能要远优与cjson,是读写json的最佳选择库之一。该库也是腾讯开源的库,很多国外的库也在使用,如ODA等;
在处理一个大文件,转出json时发生了json被截断的情况,也没有报错,真是一时不知从何下手,那就调试吧~
2.调试
心想着可能是rapidjson的bug,要本着这个目标去发现问题,从被截断的地方开始找寻后面的字符本应该是什么,发现本应写出的字符为float类型变量,其值为"-nan(ind)",嗯~,大概知道原因了,再去rapidjson的writer.h文件中调试,发现如下代码:
bool WriteDouble(double d) {
if (internal::Double(d).IsNanOrInf()) {
if (!(writeFlags & kWriteNanAndInfFlag))
return false;
if (internal::Double(d).IsNan()) {
PutReserve(*os_, 3);
PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
return true;
}
if (internal::Double(d).Sign()) {
PutReserve(*os_, 9);
PutUnsafe(*os_, '-');
}
else
PutReserve(*os_, 8);
PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
return true;
}
char buffer[25];
char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
PutReserve(*os_, static_cast<size_t>(end - buffer));
for (char* p = buffer; p != end; ++p)
PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
return true;
}
大家注意第2行和第3行:
第2行:如果要写出的double值为非数值或无穷大,要进行第3行的处理;
第3行:如果writeFlags位与kWriteNanAndInfFlag为0,则直接返回false,后续不再继续写,
其中writeFlags默认为kWriteNoFlags(0),kWriteNanAndInfFlag值为2,它俩位与为00 & 10 = 00,这就解释了为什么发生写json时被截断的问题了,其实也不是写json时被截断,是在构造json string内容时就被截断了。
3.解决
我们继续来看该怎么样设置writeFlags值。
writeFlags是模板类Writer的默认参数,显式指定值为kWriteNanAndInfFlag即可,可参考下面文章,
rapidjson::Writer<rapidjson::StringBuffer, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, rapidjson::kWriteNanAndInfFlag> writer(stringBuffer);
C++:默认模版参数_c++ 类模板 默认参数-CSDN博客
当浮点值为"-nan(ind)"时仍然写出了json。
问题解决了?还没有,请继续看下,为什么rapidjson库在浮点型值为nan时默认没有写出json?且也没有报错,是因为rapidjson不严谨吗?
json格式明确规定对于浮点类型不支持+/-Inf、NaN值,所以还需要从源头上排查为什么出现了这些值,并进行处理。
当然为了方便排查问题(let it crash),写出json时仍然可以允许写出+/-Inf、NaN,在发生问题时,充分的暴露问题,以便更好的解决问题。
4.总结
涉及到的知识点:RapidJson库、C++模板类(默认参数)、Json格式规范、位运算等。
欢迎交流:公众号:geometrylib