在github或gitee上cjson,使用库中的cJSON.c
与cJSON.h
即可。
以下是我使用cjson的案例仅供参考。
点击下载 我的cJosn使用案例
/* cJSON Types: */
#define cJSON_Invalid (0)
#define cJSON_False (1 << 0)
#define cJSON_True (1 << 1)
#define cJSON_NULL (1 << 2)
#define cJSON_Number (1 << 3)
#define cJSON_String (1 << 4)
#define cJSON_Array (1 << 5)
#define cJSON_Object (1 << 6)
#define cJSON_Raw (1 << 7) /* raw json */
/* The cJSON structure: */
typedef struct cJSON
{
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *next;
struct cJSON *prev;
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
struct cJSON *child; // 孩子节点,当为数组或对象类型才有值,基础类型为NULL
/* The type of the item, as above. */
int type;
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
char *valuestring;
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
int valueint;
/* The item's number, if type==cJSON_Number */
double valuedouble;
/* The item's name string, if this item is the child of,
or is in the list of subitems of an object. */
char *string; //键值对名字,根据名字,对象类型,获取值
} cJSON;
json字符串的解析,使用完,记得释放空间
// 传入json字符串,将字符串转换为cJSON对象,这时在堆中申请了空间,
// cJSON对象用完,需要使用cJSON_Delete(cJSON *c)函数释放空间.
cJSON * cJSON_Parse(const char *value);
cjson对象空间的释放
// 释放通过cJSON_Parse,cJSON_CreateObject等create函数申请的空间
void cJSON_Delete(cJSON *c);
判断cjson对象的类型,有以下几种类型
/* These functions check the type of an item 用于判断cJSON对象类型*/
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
创建cjson对象,使用记得释放空间
/* 创建cjson对象These calls create a cJSON item of the appropriate type. */
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
/* raw json */
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
将创建或修改的cjson对象输出为字符串,然后自己保存到文件,用完字符串需要释放空间
/* Render a cJSON entity to text for transfer/storage. */
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
申请与释放空间,cJSON_Print返回的字符串空间,可用cJSON_free释放。
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
CJSON_PUBLIC(void) cJSON_free(void *object);
对cjson库封装了几个函数,方便对json进行操作,以供参考
根据json文件路径,将文件转为json对象,失败返回NULL
cJSON * json_parse(const char *path);
在父对象中,根据键值对中的名字,获取对应的子对象,失败返回NULL
//pjson为父cjson对象, pitemname为子项名,返回子对象
const cJSON * json_get_object(const cJSON *pjson, const char *pitemname);
在父对象中,根据键值对中的名字,获取对应的字符串
//pjson为父cjson对象, pitemname为子项名,pdft为默认值,返回键值对中的值,找不到返回默认值
const char * json_get_string(const cJSON *pjson, const char *pitemname, const char *pdft);
在父对象中,根据键值对中的名字,获取对应的数值
//pjson为父cjson对象, pitemname为子项名,pdft为默认值,返回键值对中的值,找不到返回默认值
int json_get_number(const cJSON *pjson, const char *pitemname, int pdft);
在父对象中,获取类型为数组的子对象,数组成员个数
int json_get_array_size(const cJSON *pjson, const char *pitemname)
创建common.c的代码文件,并创建common.h的头文件,
common.c具体封装代码如下
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common.h"
#define in_range(c, lo, up) ((unsigned char)c >= lo && (unsigned char)c <= up)
#define isdigit(c) in_range(c, '0', '9')
/**
******************************************************************************
* @brief 字符串转换为正整数
* @param[in] : *pstr : 字符串
* @retval >= 0 : 数值
* @retval < 0 : 转换失败
******************************************************************************
*/
int
str2i(const char *pstr)
{
int ret = 0;
if (!(*pstr && isdigit(*pstr)))
return -1;
do
{
ret = ret * 10 + (*pstr - '0');
pstr++;
} while (*pstr && isdigit(*pstr));
return ret;
}
/**
******************************************************************************
* @brief 将json文件解析为json 对象
* @param[in] *path : 文件路径
* @retval cJSON * : 为NULL表示解析失败
******************************************************************************
*/
cJSON *
json_parse(const char *path)
{
int file_size = 0;
FILE *fp = NULL;
char *pstr = NULL;
cJSON *pjson = NULL;
int ret = 0;
/*
* 1. 获取文件长度
* 2. 申请内存, 读取文件
* 3. 调用cjson库解析结构
* 4. 释放内存
*/
do
{
if (!path)
{
break;
}
fp = fopen(path, "rb");
if (NULL == fp)
{
break;
}
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
pstr = malloc(file_size + 1);
if (!pstr)
{
break;
}
pstr[file_size] = 0; //last = 1
if (file_size != (int)fread(pstr, 1, file_size, fp))
{
break;
}
cJSON_Print(pjson);
pjson = cJSON_Parse(pstr);
ret = pjson ? 1 : 0;
} while (0);
if (fp)
{
fclose(fp);
}
if (pstr)
{
free(pstr);
}
return ret ? pjson : NULL;
}
/**
******************************************************************************
* @brief 获取json数组成员对象
* @param[in] *pjson : json对象
* @param[in] *pitemname : 成员
* @retval 数值
******************************************************************************
*/
const cJSON *
json_get_object(const cJSON *pjson,
const char *pitemname)
{
/*
* 1. 父子使用点(.)连接
* 2. 需要解析array, 方括号[%d]
*/
int pos;
char item[64];
char *ptmp;
char *ptr = NULL;
const char *pstr;
const cJSON *parray;
const cJSON *pobject = pjson;
if (!pjson || !pitemname || !pitemname[0] || (strlen(pitemname) >= sizeof(item)))
{
return NULL;
}
strncpy(item, pitemname, sizeof(item));
char* str = item;
//使用"."分离
while (pobject && (pstr = strtok_r(str, ".", &ptr)))
{
str = NULL;
if ((ptmp = strstr(pstr, "["))) //Array
{
if (0 > (pos = str2i(ptmp + 1)))
{
break;
}
ptmp[0] = 0;
parray = cJSON_GetObjectItem(pobject, pstr);
if (!cJSON_IsArray(parray) || (pos >= cJSON_GetArraySize(parray)))
{
break;
}
pobject = cJSON_GetArrayItem(parray, pos);
}
else //object
{
pobject = cJSON_GetObjectItem(pobject, pstr);
}
}
return pobject;
}
/**
******************************************************************************
* @brief 获取json字符串
* @param[in] *pjson : json对象
* @param[in] *pitemname : 成员
* @param[in] *pdft : 默认值
* @retval 字符串(确保非空)
******************************************************************************
*/
const char *
json_get_string(const cJSON *pjson,
const char *pitemname,
const char *pdft)
{
const char *pstr;
const cJSON *pobject;
do
{
if (!pjson || !pitemname || !pitemname[0])
{
break;
}
if (!(pobject = json_get_object(pjson, pitemname)))
{
break;
}
pstr = cJSON_GetStringValue(pobject);
return pstr ? pstr : "";
} while (0);
return pdft ? pdft : "";
}
/**
******************************************************************************
* @brief 获取json数值
* @param[in] *pjson : json对象
* @param[in] *pitemname : 成员
* @param[in] dft : 默认值
* @retval 数值
******************************************************************************
*/
int
json_get_number(const cJSON *pjson,
const char *pitemname,
int dft)
{
const cJSON *pobject;
do
{
if (!pjson || !pitemname || !pitemname[0])
{
break;
}
if (!(pobject = json_get_object(pjson, pitemname)))
{
break;
}
if (!cJSON_IsNumber(pobject))
{
break;
}
return pobject->valueint;
} while (0);
return dft;
}
/**
******************************************************************************
* @brief 获取json数组成员数
* @param[in] *pjson : json对象
* @param[in] *pitemname : 成员
* @retval 数值
******************************************************************************
*/
int
json_get_array_size(const cJSON *pjson,
const char *pitemname)
{
const cJSON *pobject;
do
{
if (!pjson || !pitemname || !pitemname[0])
{
break;
}
if (!(pobject = json_get_object(pjson, pitemname)))
{
break;
}
if (!cJSON_IsArray(pobject))
{
break;
}
return cJSON_GetArraySize(pobject);
} while (0);
return 0;
}
common.h文件
#ifndef _COMMON_H
#define _COMMON_H
#include "./json/cJSON.h"
#if defined(__cplusplus)
extern "C"
{
#endif
extern const cJSON *
json_get_object(const cJSON *pjson,
const char *pitemname);
extern const char *
json_get_string(const cJSON *pjson,
const char *pitemname,
const char *pdft);
extern int
json_get_number(const cJSON *pjson,
const char *pitemname,
int dft);
extern int
json_get_array_size(const cJSON *pjson,
const char *pitemname);
extern cJSON *
json_parse(const char *path);
#if defined(__cplusplus)
}
#endif
#endif
创建config.json
文件,文件内容如下
{
"multicastIp": "239.0.0.10",
"multicastPort": 8805,
"services": [
"192.168.0.118",
"172.19.75.111",
"172.19.75.45",
"172.19.75.234"
]
}
创建mian.c的测试文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common.h"
#define CONFIG_FILE "./config.json"
typedef struct{
int muticast_port; //心跳端口号
char * muticast_ip; //组播IP
int service_count; // 服务器数量
char** service_ips; // 服务器ip地址
} config_info_t;
config_info_t config; //配置文件信息,只供读取
/**
******************************************************************************
* @brief 初始化配置
* @retval 0: 成功, -1: 失败
******************************************************************************
*/
int config_init()
{
char key[64];
cJSON * obj = NULL;
// 检查配置文件并获取json对象
if (NULL == (obj = json_parse(CONFIG_FILE)))
{
exit(1);
}
// 获取json中的数据
config.muticast_port = json_get_number(obj, "multicastPort", 8805);
config.muticast_ip = strdup(json_get_string(obj, "multicastIp", "239.0.0.10"));
config.service_count = json_get_array_size(obj, "services");// 获取服务器个数
// 根据服务器个数, 申请空间
if (NULL == (config.service_ips = (char**) malloc(sizeof(char*) * config.service_count)))
{
cJSON_Delete(obj); //释放空间
return -1;
}
// 获取所有服务器的地址
memset(key, 0, sizeof(key));
for (int i = 0; i < config.service_count; ++i)
{
snprintf(key, sizeof(key), "services[%d]", i);
config.service_ips[i] = strdup(json_get_string(obj, key, NULL));
}
cJSON_Delete(obj); //释放json对象空间
return 0;
}
/**
******************************************************************************
* @brief 销毁配置对象, 释放空间
* @param[in] * pconfig : 配置文件对象
******************************************************************************
*/
void config_destroy()
{
if (config.muticast_ip)
{
free(config.muticast_ip);
config.muticast_ip = NULL;
}
if (config.service_ips)
{
for (int i = 0; i < config.service_count; ++i)
{
if (config.service_ips[i])
{
free(config.service_ips[i]);
config.service_ips[i] = NULL;
}
}
free(config.service_ips);
config.service_ips = NULL;
}
}
int main(int argc, char * argv[])
{
config_init();
printf("组播端口号:\t %d\n", config.muticast_port);
printf("组播 IP:\t %s\n", config.muticast_ip);
printf("服务端个数:\t %d\n", config.service_count);
for (int i = 0; i < config.service_count; i++)
{
printf("服务器%d:\t %s\n", i, config.service_ips[i]);
}
config_destroy();
}
测试结果如下
lmz@lmz-X280:~/桌面/code/c/test/cJsonTest$ make all
gcc -fPIC -c -o common.o common.c
gcc -fPIC -c -o cJSON.o ./json/cJSON.c
gcc main.c -o main common.o cJSON.o
lmz@lmz-X280:~/桌面/code/c/test/cJsonTest$ ./main
组播端口号: 8805
组播 IP: 239.0.0.10
服务端个数: 4
服务器0: 192.168.0.118
服务器1: 172.19.75.111
服务器2: 172.19.75.45
服务器3: 172.19.75.234
看到iperf中有个函数对cJSON进行了个封装,觉得挺好的,可以加入common.c
中,方便对cJSON更好的操作。
需要#include <stdarg.h>
,其功能是使用printf的形式创建cJSON对象。
/* Helper routine for building cJSON objects in a printf-like manner.
**
** Sample call:
** j = json_printf("foo: %b bar: %d bletch: %f eep: %s", b, i, f, s);
**
** The four formatting characters and the types they expect are:
** %b boolean int
** %d integer int64_t
** %f floating point double
** %s string char *
** If the values you're passing in are not these exact types, you must
** cast them, there is no automatic type coercion/widening here.
**
** The colons mark the end of field names, and blanks are ignored.
**
** This routine is not particularly robust, but it's not part of the API,
** it's just for internal iperf3 use.
*/
cJSON*
json_printf(const char *format, ...)
{
cJSON* o;
va_list argp;
const char *cp;
char name[100];
char* np;
cJSON* j;
o = cJSON_CreateObject();
if (o == NULL)
return NULL;
va_start(argp, format);
np = name;
for (cp = format; *cp != '\0'; ++cp) {
switch (*cp) {
case ' ':
break;
case ':':
*np = '\0';
break;
case '%':
++cp;
switch (*cp) {
case 'b':
j = cJSON_CreateBool(va_arg(argp, int));
break;
case 'd':
j = cJSON_CreateNumber(va_arg(argp, int64_t));
break;
case 'f':
j = cJSON_CreateNumber(va_arg(argp, double));
break;
case 's':
j = cJSON_CreateString(va_arg(argp, char *));
break;
default:
va_end(argp);
return NULL;
}
if (j == NULL) {
va_end(argp);
return NULL;
}
cJSON_AddItemToObject(o, name, j);
np = name;
break;
default:
*np++ = *cp;
break;
}
}
va_end(argp);
return o;
}
cJSON* json_printf(const char *format, ...);
使用示例
int main(int argc, char * argv[])
{
char ip[] = "127.0.0.1";
int port = 8080;
cJSON * cjobj = cJSON_CreateObject();
/*printf的形式创建对象*/
cJSON * cjip = json_printf("ip: %s port: %d", ip, port);
cJSON_AddItemToObject(cjobj, "service", cjip);
char * p = cJSON_Print(cjobj);
printf("%s \n", p);
cJSON_free(p);
cJSON_Delete(cjobj);
}