本文要点:
处理10k的json数据大概会额外用掉50k左右的ram,谨记,没那么大空间预留就别玩了
cJSON库下载
cJSON-master.zip-其它文档类资源-CSDN下载 (应该是被我设置0积分下载的)
https://github.com/DaveGamble/cJSON (github下载)
cJSON解析:
使用cJSON之前先了解下其数据结构(在cJSON.h文件)
/* The cJSON structure: */
typedef struct cJSON {
struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
int type; /* The type of the item, as above. */
char *valuestring; /* The item's string, if type==cJSON_String */
int valueint; /* The item's number, if type==cJSON_Number */
double valuedouble; /* The item's number, if type==cJSON_Number */
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
} cJSON;
其中valuestring,valueint,valuedouble就是你所需要字段的值,具体用法看下面吧。
下面给出一个实例:
{
"code": 0,
"data": {
"list1": {
"define1": "this is define 1",
"define2": "this is define 2"
},
"list2": [
{
"intNum": 33,
"doubleNum": 12.1
}
]
},
"detailMsg": "",
"errorCode": 0,
"extMap": {},
"fail": true,
"msg": "",
"success": true
}
我们可以看到这块数据有3层,第一步先解析整个json
假如整个json用buffer变量装着
cJSON *root=NULL,*L2Object = NULL,*L3Object = NULL ;//root表示最开始层,L2表示第二层,L3表示第三层
char* buffer;//这里当buffer里面已经有数据了
if(!(root = cJSON_Parse((char*)buffer)))
{
return ; //这里表示root返回值是空,表示解析json失败
}
1.获取code的值,从上面可以看到code的值是一个整数(其他同理):
code = cJSON_GetObjectItem(root,"code")->valueint;
2.获取data里面字段的值,先需要获取到data相对应的控制指针
L2Object = cJSON_GetObjectItem(root,"data");
这样就得到data的控制指针,然后同理可进入第三层
那么获取define1,2的值:
L3Object = cJSON_GetObjectItem(L2Object ,"list1");先获取到list1指针
define1 = cJSON_GetObjectItem(L3Object ,"define1")->valuestring;
define2 = cJSON_GetObjectItem(L3Object ,"define2")->valuestring;
那么获取intNum,doubleNum的值:
L3Object = cJSON_GetObjectItem(L2Object ,"list2");先获取到list2指针
intNum= cJSON_GetObjectItem(L3Object ,"intNum")->valuent;
doubleNum= cJSON_GetObjectItem(L3Object ,"doubleNum")->valuedouble;
3.获取true,false的值
介绍下type的值(在cJSON.h文件)
/* cJSON Types: */
#define cJSON_False 0
#define cJSON_True 1
#define cJSON_NULL 2
#define cJSON_Number 3
#define cJSON_String 4
#define cJSON_Array 5
#define cJSON_Object 6
if(cJSON_GetObjectItem(root,"fail")->type == cJSON_True)
{printf("fail is ture");}
至此这种类型就是这样获得
还有解析数组类的
[
{
"new1": "",
"new2": ""
},
{
"new1": "",
"new2": ""
}
]
同样(下面默认都是正常获取到,不考虑异常),
root = cJSON_Parse((char*)buffer);
if( NULL != root )
{
cJSON *L2Object = root ->child;
while( L2Object != NULL )
{
char * new1 = cJSON_GetObjectItem( client_list , "new1")->valuestring ;
char * new2= cJSON_GetObjectItem( client_list , "new2")->valuestring ;
printf("new1: %s new2: %s\r\n",new1,new2);
L2Object = L2Object ->next ;
}
}
{
"list": [
"0.0.0.0",
"1.1.1.1",
"2.2.2.2"
]
}
root = cJSON_Parse((char*)buffer);
L2Object = cJSON_GetObjectItem(root,"list");
int array_size = cJSON_GetArraySize ( L2Object );//获取list有多少个数据
for( iCnt = 0 ; iCnt < array_size ; iCnt ++ )
{
cJSON * pSub = cJSON_GetArrayItem(L2Object , iCnt);
if(NULL == pSub ){ continue ; }
char * ivalue = pSub->valuestring ;
printf("list[%d] : %s\r\n",iCnt,ivalue);
}
cJSON生成:
首先,来个最普通常见的
{
"define1": "this is define1",
"define2": "this is define2",
"numInt": 12,
"numDouble": 12.12,
"sta": true
}
cJSON*root = cJSON_CreateObject();//创建一个目录并申请内存
cJSON*item = NULL;//用于创建一个字段
char *out;
double num = 12;
/*写法1*/
item = cJSON_CreateString("this is define1");
cJSON_AddItemToObject(root, "define1", item);//这里item申请的内存会转到root上,不需要手动释放,其他同理
item = cJSON_CreateString("this is define2");
cJSON_AddItemToObject(root, "define2", item);
item = cJSON_CreateNumber(num);
cJSON_AddItemToObject(root, "numInt", item);
item = cJSON_CreateNumber(12.12);
cJSON_AddItemToObject(root, "numDouble", item);
item = cJSON_CreateTrue();
cJSON_AddItemToObject(root, "sta", item);
out = cJSON_Print(root); //注意,这里不是打印输出,是将json格式化输出到一块内存上,并返回指针
printf("%s\n", out); //这里才是打印显示
cJSON_Delete(root);
free(out); //这两处必须释放内存,否则会造成内存泄漏。
/*写法2,直接省略使用item的步骤,下面的方法默认用这个来做*/
cJSON_AddItemToObject(root, "define1", cJSON_CreateString("this is define1"));
cJSON_AddItemToObject(root, "define2", cJSON_CreateString("this is define2"));
cJSON_AddItemToObject(root, "numInt", cJSON_CreateNumber(num));
cJSON_AddItemToObject(root, "numDouble", cJSON_CreateNumber(12.12));
cJSON_AddItemToObject(root, "sta", cJSON_CreateTrue());
out = cJSON_Print(root);
printf("%s\n", out);
cJSON_Delete(root);
free(out);
PS:
对于out = cJSON_Print(root);这条,其实常用的是另外一个输出函数 char *cJSON_PrintUnformatted(cJSON *item) 这个,两者的区别是上面那个是格式化输出,就是人看起来比较直观,但是只是给人看的,不是给程序看的(看上面的例子)。下面这个生成就是正常地生成,一行过。具体可自行输出看看。
然后,下一个
{
"object1": {
"firstName": "Tony",
"lastName": "Jeny"
},
"object2": {
"movie": "Now You See Me"
}
}
其实可以吧json看成一个文件系统,root就是根目录,object1,object2就是根目录下的子目录,firstName就是文件。再想往下建目录就同理操作即可
cJSON *root = cJSON_CreateObject(); //相当于根目录
cJSON *obj_floor1; //相当于子目录
obj_floor1 = cJSON_CreateObject();
cJSON_AddItemToObject(obj_floor1, "firstName", cJSON_CreateString("Tony"));
cJSON_AddItemToObject(obj_floor1, "lastName", cJSON_CreateString("Jeny"));
cJSON_AddItemToObject(root, "object1", obj_floor1); //将obj_floor1放到root下并命名为object1
obj_floor1 = cJSON_CreateObject();
cJSON_AddItemToObject(obj_floor1, "movie", cJSON_CreateString("Now You See Me"));
cJSON_AddItemToObject(root, "object2", obj_floor1);
out = cJSON_Print(root);
printf("%s\n", out);
cJSON_Delete(root);
free(out);
再下一个(数组型)
[{
"lastName": "我是谁",
"age": 123
}, {
"lastName": "你是谁",
"sta": true,
"age": 321
}]
cJSON*array = cJSON_CreateArray();
cJSON*obj_person
char *out;
obj_person = cJSON_CreateObject();
cJSON_AddItemToObject(obj_person, "lastName", cJSON_CreateString("我是谁"));
cJSON_AddItemToObject(obj_person, "age", cJSON_CreateNumber(123));
cJSON_AddItemToArray(array, obj_person);
obj_person = cJSON_CreateObject();
cJSON_AddItemToObject(obj_person, "lastName", cJSON_CreateString("你是谁"));
cJSON_AddItemToObject(obj_person, "sta", cJSON_CreateTrue());
cJSON_AddItemToObject(obj_person, "age", cJSON_CreateNumber(321));
cJSON_AddItemToArray(array, obj_person);
out = cJSON_Print(array);
printf("%s\n", out);
cJSON_Delete(array);
free(out);
补充(后续可能会有更新)
1.如果使用cJSON_CreateNumber()后,发现输出的数小数点后的位数特别多(有可能是旧版本有这个问题吧,具体自行测测)
如 cJSON_AddItemToObject(root, "numDouble", cJSON_CreateNumber(12.12));
得到结果是 "numDouble": 12.12000000 无法限制小数位后面的位数
更改如下(修改cJSON.c文件)
static char *print_number(cJSON *item,printbuffer *p)
{
char *str=0;
double d=item->valuedouble;
if (d==0)
{
if (p) str=ensure(p,2);
else str=(char*)cJSON_malloc(2); /* special case for 0. */
if (str) strcpy(str,"0");
}
else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
{
if (p) str=ensure(p,21);
else str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
if (str) sprintf(str,"%d",item->valueint);
}
else
{
if (p) str=ensure(p,64);
else str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */
if (str)
{
if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d);
else sprintf(str,"%f",d);
}
}
return str;
}
最后一个sprintf(str,"%f",d);改成sprintf(str,"%.2lf",d);
这样可以限制输出小数点后两位