jsonCpp使用介绍和优化

前端之家收集整理的这篇文章主要介绍了jsonCpp使用介绍和优化前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。



JsonCpp简介

  • JsonCpp主要包含三种类型的class:Value Reader Writer。
  • jsoncpp中所有对象、类名都在namespace json中,包含json.h即可。

注意: Json::Value只能处理ANSI类型的字符串,如果C++程序使用Unicode编码的,最好加一个Adapt类来适配。


简单解析例子:

数据格式为:

  1. {
  2.     "status":"ok",   "data":
  3.    {
  4.    "id":"18135798",   "name":"\u6b27\u9ea6\u560e\u5730",  "avatar":"http:\/\/u1.qhimg.com\/qhimg\/quc\/48_48\/22\/02\/55\/220255dq9816.3eceac.jpg?f=6c449fbaaa093e52b4053e46170af079",  "sex":"\u672a\u77e5",  "area":"",  "nick":"","access_token":"49395625948d4d6f253203e8aa8f3316150290e9d57be59b2","refresh_token":"493956259454b771dba785feeafb01221858440f4c811b5ad"
  5.    },    "common":
  6. {
  7. "channel":"000023","user_sdk":"360","uid":"18135798"
  8. "server_id":""
  9. },   "ext":""
  10.   }


  1. //解析json
  2. int32_t index = reponse_data.find("{");
  3. if(-1 != index) {
  4. string in_data = reponse_data.substr(index,reponse_data.size()-index);
  5. Json::Reader reader;
  6. Json::Value value;
  7. if(reader.parse(in_data,value)) {
  8. if(value["status"].asString() == "ok") {
  9. if(!value["data"].isNull()) {
  10. Json::Value data = value["data"];
  11.  
  12. if (!data["nickname"].isNull()) {
  13. const char *name = data["nickname"].asCString();
  14. memcpy(plat_user->nick_name_,name,strlen(name));
  15. }
  16.  
  17. if (!data["token"].isNull()) {
  18. const char *token = data["token"].asCString();
  19. memcpy(s_data->token,token,strlen(token));
  20. s_data->token[32] = '\0';
  21. }
  22. }
  23.  
  24. if(!value["common"].isNull()) {
  25. Json::Value data = value["common"];
  26. if (!data["channel"].isNull()) {
  27. const char *channel = data["channel"].asCString();
  28. memcpy(s_data->plat,channel,strlen(channel));
  29. }
  30.  
  31. if (!data["uid"].isNull()) {
  32. const char *uid = data["uid"].asCString();
  33. memcpy(plat_user->user_id_,uid,strlen(uid));
  34. }
  35. }
  36.  
  37. return 0;
  38. } else {
  39. return -1;
  40. }
  41. }
  42. }


下载和编译

本文运行环境是: Redhat 5.5 + g++version 4.6.1 + GNU Make 3.81 + jsoncpp-0.5.0

下载地址是:http://sourceforge.net/projects/jsoncpp/

解压之后得到jsoncpp-src-0.5.0文件夹,我们只需要jsoncpp的头文件和cpp文件,其中jsonscpp的头文件位于jsoncpp-src-0.5.0\include\json,jsoncpp的cpp文件位于jsoncpp-src-0.5.0\src\lib_json。

这里我列出我们的工作目录:

  1. jsoncpp/ //工作目录
  2. |-- include //头文件根目录
  3. |  |-- json //json头文件,对应jsoncpp-src-0.5.0\include\json
  4. |-- src //cpp源码文件根目录
  5.   |-- json //jsoncpp源码文件,对应jsoncpp-src-0.5.0\src\lib_json
  6.   |-- main.cpp //我们的主函数调用jsoncpp的示例代码
  7.  
  8. |-- makefile //makefile,不用我们多说了吧,不懂请看我博客的makefile最佳实践

反序列化Json对象

假设有一个json对象如下:

  1. { "name":"json″,"array": [ { "cpp": "jsoncpp" },{ "javajsoninjavaPHPsupport" } ] }
我们要实现这个json的反序列化代码如下:
  1. void readJson() {
  2. using namespace std;
  3. std::string strValue = "{\"name\":\"json\",\"array\":[{\"cpp\":\"jsoncpp\"},{\"java\":\"jsoninjava\"},{\"PHP\":\"support\"}]}";
  4.  
  5. Json::Reader reader;
  6. Json::Value value;
  7.  
  8. if (reader.parse(strValue,value))
  9. {
  10. std::string out = value["name"].asString();
  11. std::cout << out << std::endl;
  12. const Json::Value arrayObj = value["array"];
  13. for (unsigned int i = 0; i < arrayObj.size(); i++)
  14. {
  15. if (!arrayObj[i].isMember("cpp"))
  16. continue;
  17. out = arrayObj[i]["cpp"].asString();
  18. std::cout << out;
  19. if (i != (arrayObj.size() - 1))
  20. std::cout << std::endl;
  21. }
  22. }
  23. }

序列化Json对象

  1. void writeJson() {
  2. using namespace std;
  3.  
  4. Json::Value root;
  5. Json::Value arrayObj;
  6. Json::Value item;
  7.  
  8. item["cpp"] = "jsoncpp";
  9. item["java"] = "jsoninjava";
  10. item["PHP"] = "support";
  11. arrayObj.append(item);
  12.  
  13. root["name"] = "json";
  14. root["array"] = arrayObj;
  15.  
  16. root.toStyledString();
  17. std::string out = root.toStyledString();
  18. std::cout << out << std::endl;
  19. }


JsonCpp使用优化



最近一个项目在使用JsonCpp,JsonCpp简洁易用的接口让人印象深刻。但是在实际使用过程中,我发现JsonCpp的性能却不尽如人意,所以想着方法优化下性能

代码理解

1、JsonCpp中一切都是Value,Value用union指向自己保存的数据。Value的类型分为两种,一种是容器类型,比如arrayValue和objectValue。二者都是用map保存数据,只是arrayValue的key为数字而已。另外一种是基本类型,比如字符串,整型数字等等。

2、解释JSON数据时,JsonCpp在operator[]函数开销比较大。JsonCpp内部使用std::map,map在查找性能上不如hash_map,但是将map替换成hash_map有一定的困难,因为map的key为CZString,而这个类又是Value的内部类,导致不能定义hash_map需要的hash结构体。

本来想尝试下internal map,结果开启JSON_VALUE_USE_INTERNAL_MAP这个宏之后,根本通不过编译,因为value.h中有一处uion声明里面居然放的是结构体,不知道什么编译器支持这种语法。

基准测试程序

  1. #include <iostream>
  2. #include <string>
  3. #include <sys/time.h>
  4. #include <time.h>
  5. #include <json/json.h>
  6. using namespace std;
  7. int64_t getCurrentTime()
  8. {
  9. struct timeval tval;
  10. gettimeofday(&tval,NULL);
  11. return (tval.tv_sec * 1000000LL + tval.tv_usec);
  12. }
  13. char * str = "abcdefghijklmnopqrstuvwxyz";
  14. void test1()
  15. {
  16. int doc_count = 40;
  17. int outer_field_count = 80;
  18. Json::Value common_info;
  19. int64_t start_time = getCurrentTime();
  20. for(size_t i=0; i<doc_count; ++i)
  21. {
  22. Json::Value auc_info;
  23. for( size_t j=0 ; j<outer_field_count; ++j )
  24. {
  25. auc_info.append(str);
  26. }
  27. common_info.append(auc_info);
  28. }
  29. int64_t end_time = getCurrentTime();
  30. cout << "append time: " << end_time - start_time << endl;
  31. }
  32. void test2()
  33. {
  34. int doc_count = 40;
  35. int outer_field_count = 80;
  36. Json::Value common_info;
  37. int64_t start_time = getCurrentTime();
  38. Json::Value auc_info;
  39. for(size_t i=0; i<doc_count; ++i)
  40. {
  41. for( size_t j=0 ; j<outer_field_count; ++j )
  42. {
  43. auc_info[j] = str;
  44. }
  45. common_info.append(auc_info);
  46. }
  47. int64_t end_time = getCurrentTime();
  48. cout << "opt append time: " << end_time - start_time << endl;
  49. }
  50. void test3()
  51. {
  52. int doc_count = 40;
  53. int outer_field_count = 80;
  54. Json::Value common_info;
  55. int64_t start_time = getCurrentTime();
  56. Json::Value auc_info;
  57. for(size_t i=0; i<doc_count; ++i)
  58. {
  59. for( size_t j=0 ; j<outer_field_count; ++j )
  60. {
  61. auc_info[j] = Json::StaticString(str);
  62. }
  63. common_info.append(auc_info);
  64. }
  65. int64_t end_time = getCurrentTime();
  66. cout << "StaticString time: " << end_time - start_time << endl;
  67. }
  68. int main(int argc,const char *argv[])
  69. {
  70. test1();
  71. test2();
  72. test3();
  73. return 0;
  74. }


编译优化

默认情况下,JsonCpp编译时并没有带优化参数,自己可以加上优化参数。Linux环境下在下面这段代码中的CCFLAGS加入”O2″。

elifplatform.startswith('linux-gcc'):
env.Tool('default')
env.Append( LIBS =['pthread'],CCFLAGS ="-Wall -fPIC O2" )
env['SHARED_LIB_ENABLED']=True

可以看到使用O2优化比默认编译的版本性能提升一倍多。

append time: 4946
opt append time: 3326
StaticString time: 2750

append time: 1825
opt append time: 1082
StaticString time: 845

使用方法上的优化

测试代码中第三种方法比第一种方法效率提升了一倍多。第三种方法之所以效率更高,有两个原因。

1、首先是在循环中一直复用auc_info对象。第一个循环就能将auc_info的长度初始化为doc_count。通过下标的访问方法,一直复用数组中的元素。

2、如果key和value内存不会被释放,那么使用StaticString效率会更高,省去了构造CZString时拷贝的开销。

代码优化

因为在JsonCpp中一切都是Value,所以会有大量的隐性类型转换,要构造大量的Value对象。为了提高性能,可以在实现绕过这个机制,牺牲一致性。

因为Value最常用的类型是字符串,因此给Value增加一个setValue函数

void Value::setValue(constStaticString& value )
{
type_ = stringValue;
allocated_ = false;
value_.string_ = const_cast<char*>( value.c_str() );
}

再测试一下性能,可以发现性能较第三种方法还有提升。
append time: 1849
opt append time: 1067
StaticString time: 843
setValue time: 570

最后还有一个办法就是静态链接。JsonCpp库本身非常小,将其静态链接能稍微提升一点性能。下面是静态链接时基准测试程序的耗时情况。
append time: 1682
opt append time: 1011
StaticString time: 801
setValue time: 541

参考:

http://www.searchtb.com/2012/11/jsoncpp-optimization.html

http://outofmemory.cn/code-snippet/1546/c-usage-jsonCpp-process-json-data

猜你在找的Json相关文章