首页 > 代码库 > 对json的爱恨情仇
对json的爱恨情仇
本文回顾了对json的爱恨情仇. C++有风险,使用需谨慎.
在工作时才接触json,看过简介,语法简单,易于扩展,用起来是很爽的事.和后端的一些交互也基本上都是用的json.在项目中用了第三方库:simple json,用起来也不亦乐乎.不过也吃过该库的亏:
1.忘了解析后的JSONValue应该delete掉;
2.simple json出来的其中的数字用double表示,但是server给的是64位整数.于是我小小修改一点使得解析出来数的时候同时保留原始的number literal. [使用double表示int的话一般而言53位整数内是OK的.大概算法是在IEEE754中双精度浮点数去掉符号1位和指数11位为64-1-11=52的尾数.2的52次方是4503599627370496,简记为4.5*10^15. 参考:http://zh.wikipedia.org/zh-cn/IEEE_754 和 http://bolt.xunlei.com/faq.html ]
3.需要注意json在array最后一个元素后的逗号的处理;
4.json串本身是什么编码,库在解析使uxxxx的形式的字符的时候是不是OK.(记得在jsoncpp中出过问题,后来使用了chromium里base里的Value.如果不是提前和server端和其它端讨论这个问题,说不定又被坑了.这是在动摇信念后的事了).
但是这些坑都无法动摇我对json的信念,直到有一天,我导师给了我一个1685366字节的json数据我用simple json解析的时候花了十几秒(笔记本上),使得在以下的几年内对json无法直视.每当别人使用json的时候我会说:哥有个不到2M的json数据,能让你的解析速度很慢,十几秒喔. 每每遇到需要处理格式化的内容时,我就转向了xml的怀抱,而相对熟悉的是rapidxml.但是rapidxml也有坑啊:
1.rapidxml在原有文档上修改. 所以在解析前最好是拷贝一份输入.
2.格式化的时候,很多都是指针操作,你不能临时new一个出来,或者指向临时的变量.而要专门开辟一个存储区域,需要的时候在里面放字符串,格式化完成后再统一回收.
3.格式化的时候最好用sstream,否则速度会慢点.
4.需要捕获异常.
5.最好只处理utf8的串. 如果是utf16,在结点属性,或者文本结点上放个中文"一",试试,马上就异常了.
直到后来,我更懒了,更喜欢http的header的格式.一个key加一个":",后面跟value.不同的kv用"\r\n"分割.很快就能写一个解析这样的数据的代码.
--------------------------------------------------------------------------
直到昨天,也是老罗和自如大战后的第N天,我想:我也来测评一下那几个json库吧.参战的是:SimpleJSON,jsoncpp,libjson,rapidjson. 挑战目标是那个传说中的1685366字节的json文件. 只作文件解析.
几个库都还大,共同点是:现在都喜欢移到github上了. 比如SimpleJSON迁到github上的时候我只有download下来master上的代码. 其老巢mjpa.co.uk一打开就是File not found.不过后来对比了一下代码,目测master上的代码可以直接当release的使用. 几个开发者在软件维护性上的黑魔法[参考:http://blog.jobbole.com/76216/]比较少,还算比较人道,很容易就编译出来了.其中稍微黑一点的是libjson,需要自己去关一下C接口.调试版本需要开一个宏. jsoncpp是灰色的,需要用scons,但是我没弄成功. 在makefiles下找到了vs工程,升级一下就能用.
人懒,写的测试代码只是勉强能用.大概是一个函数读了个文件,把utf8和utf16输出到两个全局变量里. 定义了个:
void simple_json_test(const char* utf8, const wchar_t* utf16);
void rapid_json_test(const char* utf8, const wchar_t* utf16);
void json_cpp_test(const char* utf8, const wchar_t* utf16);
void lib_json_test(const char* utf8, const wchar_t* utf16);
在主函数里调用这些函数. 用clock()函数计时. 每次换一个函数,重新编译后就有结果.具体测试函数体加起来11行, 有些代码连资源释放也懒得写了.
SimpleJSON:56,62,57
rapidjson:16,16,15
jsoncpp:60,45,68
libjson:9,9,16
该结果使得我恢复了对json的信仰,但是不明白SimpleJSON前后差异为什么那么大.找出以前的SimpleJSON的库,重新跑了一次结果是:
SimpleJSON_old:6893,6826,6844
vs的性能分析没仔细看,简单的代码review后发现改变并不大,但是最终还是被我发现猫腻所在.
在JSON.h中有个函数:
在JSON.cpp中181行,JSONValue.cpp中62,70行被引用,而老版本中的对应代码是:
如果将老版本的这三处换为新版本的则问题解决. 当然,替换前后对比,问题是什么也很明显.
本文相关代码在:http://download.csdn.net/detail/baihacker/7862785
其中的测试数据不在里面,因为这是项目开发中用到的,需要保密.
在工作时才接触json,看过简介,语法简单,易于扩展,用起来是很爽的事.和后端的一些交互也基本上都是用的json.在项目中用了第三方库:simple json,用起来也不亦乐乎.不过也吃过该库的亏:
1.忘了解析后的JSONValue应该delete掉;
2.simple json出来的其中的数字用double表示,但是server给的是64位整数.于是我小小修改一点使得解析出来数的时候同时保留原始的number literal. [使用double表示int的话一般而言53位整数内是OK的.大概算法是在IEEE754中双精度浮点数去掉符号1位和指数11位为64-1-11=52的尾数.2的52次方是4503599627370496,简记为4.5*10^15. 参考:http://zh.wikipedia.org/zh-cn/IEEE_754 和 http://bolt.xunlei.com/faq.html ]
3.需要注意json在array最后一个元素后的逗号的处理;
4.json串本身是什么编码,库在解析使uxxxx的形式的字符的时候是不是OK.(记得在jsoncpp中出过问题,后来使用了chromium里base里的Value.如果不是提前和server端和其它端讨论这个问题,说不定又被坑了.这是在动摇信念后的事了).
但是这些坑都无法动摇我对json的信念,直到有一天,我导师给了我一个1685366字节的json数据我用simple json解析的时候花了十几秒(笔记本上),使得在以下的几年内对json无法直视.每当别人使用json的时候我会说:哥有个不到2M的json数据,能让你的解析速度很慢,十几秒喔. 每每遇到需要处理格式化的内容时,我就转向了xml的怀抱,而相对熟悉的是rapidxml.但是rapidxml也有坑啊:
1.rapidxml在原有文档上修改. 所以在解析前最好是拷贝一份输入.
2.格式化的时候,很多都是指针操作,你不能临时new一个出来,或者指向临时的变量.而要专门开辟一个存储区域,需要的时候在里面放字符串,格式化完成后再统一回收.
3.格式化的时候最好用sstream,否则速度会慢点.
4.需要捕获异常.
5.最好只处理utf8的串. 如果是utf16,在结点属性,或者文本结点上放个中文"一",试试,马上就异常了.
直到后来,我更懒了,更喜欢http的header的格式.一个key加一个":",后面跟value.不同的kv用"\r\n"分割.很快就能写一个解析这样的数据的代码.
--------------------------------------------------------------------------
直到昨天,也是老罗和自如大战后的第N天,我想:我也来测评一下那几个json库吧.参战的是:SimpleJSON,jsoncpp,libjson,rapidjson. 挑战目标是那个传说中的1685366字节的json文件. 只作文件解析.
几个库都还大,共同点是:现在都喜欢移到github上了. 比如SimpleJSON迁到github上的时候我只有download下来master上的代码. 其老巢mjpa.co.uk一打开就是File not found.不过后来对比了一下代码,目测master上的代码可以直接当release的使用. 几个开发者在软件维护性上的黑魔法[参考:http://blog.jobbole.com/76216/]比较少,还算比较人道,很容易就编译出来了.其中稍微黑一点的是libjson,需要自己去关一下C接口.调试版本需要开一个宏. jsoncpp是灰色的,需要用scons,但是我没弄成功. 在makefiles下找到了vs工程,升级一下就能用.
人懒,写的测试代码只是勉强能用.大概是一个函数读了个文件,把utf8和utf16输出到两个全局变量里. 定义了个:
void simple_json_test(const char* utf8, const wchar_t* utf16);
void rapid_json_test(const char* utf8, const wchar_t* utf16);
void json_cpp_test(const char* utf8, const wchar_t* utf16);
void lib_json_test(const char* utf8, const wchar_t* utf16);
在主函数里调用这些函数. 用clock()函数计时. 每次换一个函数,重新编译后就有结果.具体测试函数体加起来11行, 有些代码连资源释放也懒得写了.
SimpleJSON:56,62,57
rapidjson:16,16,15
jsoncpp:60,45,68
libjson:9,9,16
该结果使得我恢复了对json的信仰,但是不明白SimpleJSON前后差异为什么那么大.找出以前的SimpleJSON的库,重新跑了一次结果是:
SimpleJSON_old:6893,6826,6844
vs的性能分析没仔细看,简单的代码review后发现改变并不大,但是最终还是被我发现猫腻所在.
在JSON.h中有个函数:
// Simple function to check a string 's' has at least 'n' characters static inline bool simplejson_wcsnlen(const wchar_t *s, size_t n) { if (s == 0) return false; const wchar_t *save = s; while (n-- > 0) { if (*(save++) == 0) return false; } return true; }
在JSON.cpp中181行,JSONValue.cpp中62,70行被引用,而老版本中的对应代码是:
// We need 5 chars (4 hex + the 'u') or its not valid if (wcslen(*data) < 5) // Is it a boolean? else if ((wcslen(*data) >= 4 && wcsncasecmp(*data, L"true", 4) == 0) || (wcslen(*data) >= 5 && wcsncasecmp(*data, L"false", 5) == 0)) // Is it a null? else if (wcslen(*data) >= 4 && wcsncasecmp(*data, L"null", 4) == 0)
如果将老版本的这三处换为新版本的则问题解决. 当然,替换前后对比,问题是什么也很明显.
对json的爱恨情仇
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。