本文回想了对json的爱恨情仇. C++有风险,使用需慎重.

本文相关代码在: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/]比較少,还算比較人道,非常easy就编译出来了.当中略微黑一点的是libjson,须要自己去关一下C接口.调试版本号须要开一个宏.
jsoncpp是灰色的,须要用scons,可是我没弄成功. 在makefiles下找到了vsproject,升级一下就能用.



人懒,写的測试代码仅仅是勉强能用.大概是一个函数读了个文件,把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的爱恨情仇的更多相关文章

  1. Menu与ActionBar的爱恨情仇

    最近在开发一款音乐播放器,在开发过程中遇到了一点小麻烦,通过android API搞清楚了Menu与ActionBar的爱恨情仇,写了个小Demo祭奠一下那些年我们陷进去的坑,有不对的地方请大神们批评 ...

  2. web移动端fixed布局和input等表单的爱恨情仇 - 终极BUG,完美解决

    [问题]移动端开发,ios下当fixed属性和输入框input(这里不限于input,只要可以调用移动端输入法的都包括,如:textarea.HTML5中contenteditable等),同时存在的 ...

  3. 注解:大话AOP与Android的爱恨情仇

    转载:大话AOP与Android的爱恨情仇 1. AOP与OOP的区别 平时我接触多的就是OOP(Object Oriented Programming面向对象).AOP(Aspect Oriente ...

  4. 除了love和hate,还能怎么表达那些年的“爱恨情仇”?

    实用英语 帮你全面提高英语水平 关注 童鞋们每次刷美剧的时候,相信都会被CP感满满的男女主角虐得体无完肤吧. 可是,一到我们自己表达爱意或者恨意的时候,却苦于词穷,只会用love, like, hat ...

  5. String、StringBuilder、StringBuffer的爱恨情仇

    第三阶段 JAVA常见对象的学习 StringBuffer和StringBuilder类 (一) StringBuffer类的概述 (1) 基本概述 下文以StringBuffer为例 前面我们用字符 ...

  6. [转帖]探秘华为(一):华为和H3C(华三)的爱恨情仇史!

    探秘华为(一):华为和H3C(华三)的爱恨情仇史! https://baijiahao.baidu.com/s?id=1620703498823290828&wfr=spider&fo ...

  7. Tidyverse|数据列的分分合合,爱恨情仇

    Tidyverse|数据列的分分合合,爱恨情仇 本文首发于“生信补给站”Tidyverse|数据列的分分合合,一分多,多合一 TCGA数据挖掘可做很多分析,前期数据“清洗”费时费力但很需要. 比如基因 ...

  8. pytorch和tensorflow的爱恨情仇之基本数据类型

    自己一直以来都是使用的pytorch,最近打算好好的看下tensorflow,新开一个系列:pytorch和tensorflow的爱恨情仇(相爱相杀...) 无论学习什么框架或者是什么编程语言,最基础 ...

  9. pytorch和tensorflow的爱恨情仇之定义可训练的参数

    pytorch和tensorflow的爱恨情仇之基本数据类型 pytorch和tensorflow的爱恨情仇之张量 pytorch版本:1.6.0 tensorflow版本:1.15.0 之前我们就已 ...

随机推荐

  1. python练习2 购物车程序

    # -*- coding: utf-8 -*-# @Time : 2018/10/18 16:06# @Author : Two Brother# @EMAIL : yeluyide@163.com# ...

  2. vue之props传值与单向数据流

    (1)组件通信 父组件向子组件传递数据.这个正向传递数据的过程就是通过props来实现的. 两者区别:props中声明的数据与组件data函数return返回的数据的主要区别就是props来自父级,而 ...

  3. find_in_set()和in()比较

    转载于:https://www.cnblogs.com/zqifa/p/mysql-4.html 作者:zqifa 因为自己太懒了,就从大佬那转载来,作为一次笔记! mysql 中find_in_se ...

  4. buf.slice()

    buf.slice([start[, end]]) start {Number} 默认:0 end {Number} 默认:buffer.length 返回:{Buffer} 返回一个指向相同原始内存 ...

  5. 在rubymine中集成heroku插件

    先安装heroku,参见http://www.cnblogs.com/jecyhw/p/4906990.html Heroku安装之后,就自动安装上git,目录为C:\Program Files (x ...

  6. rbac组件之菜单操作(三)

    菜单包括菜单列表,菜单列表不仅将菜单列出来,而且将每个菜单下的权限也列出来.菜单的添加.删除.修改. urls.py ... re_path(r'^menus/list/$', MenuView.as ...

  7. (十二)python3 迭代器

    可以直接作用于 for 循环的对象统称为可迭代对象: Iterable .一类是集合数据类型,如 list . tuple . dict . set . str 等,一类是 generator ,包括 ...

  8. 使用js生成条形码以及二维码

    一.用js生成条形码这种业务场景不是很常见的,最近刚好又接到这种需求 Google一下,发现github还真有这方面的轮子,感谢github,省去了我们很多造轮子的过程, 好了言归正传,首先引入jsb ...

  9. GPIO——端口位设置/清除寄存器BSRR,端口位清除寄存器BRR

    端口位设置/复位寄存器BSRR: 注:如果同时设置了BSy和BRy的对应位,BSy位起作用. 位31:16  BRy: 清除端口x的位y (y = 0…15)      这些位只能写入并只能以字(16 ...

  10. WSS、SSL 和 https 之间的关系

    SSL SSL(Secure Socket Layer,安全套接层) 简单来说是一种加密技术, 通过它, 我们可以在通信的双方上建立一个安全的通信链路, 因此数据交互的双方可以安全地通信, 而不需要担 ...