当前位置: 首页 > news >正文

OpenHarmony之cJSON库使用介绍

一、前言

我们前面OpenHarmony设备配网 文章中,给大家提供的示例有使用cJSON解析和cJSON创建json数据的用法

那么有同学会提出疑问,我难道只能用cJSON库?

当然不是啊,你也可以用 json-parser、parson、jansson 等等三方库

回到正题,我们如何在OpenHarmony中,灵活熟练的使用cJSON库呢?

如果对JSON本身就不懂的,别急我们先带大家理解JSON,然后再去深入学习cJSON库的使用。

二、JSON理解

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。
JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等), 这些特性使JSON成为理想的数据交换语言。

我们可以在Be JSON中随便输入一个内容,查看报错的提示:

我们能看到期望的是如下格式的数据:

字符串、数字Number、NULL、BOOL、Json对象、Json数组,这些格式的数据


那么我们在JSON中,常用的(Json对象、Json数组) 2种数据格式:


Json对象


Json数组

1、Json对象

Json对象使用的是 { } 来描述,每个 Json 对象中都可以存储若干个元素,每一个元素都对应一个键值对(key:value 结构),元素和元素之间使用逗号间隔
key必须是字符串,value值类型可选,如:字符串、数字、Boolean、NULL、Json对象、Json数组

{"count": 100,"flag": true,"paras": {"Light": "ON","Motor": "OFF"}
}

2、Json数组

Json数组使用的是 [ ] 来描述,[ ]里面的元素和元素之间使用逗号间隔,支持的数据类型:字符串、数字、Boolean、NULL、Json对象、Json数组

// 整形
[996,2399,1999,6999]
// 字符串
["张三", "李四", "王二", "麻子"]
// 混合使用
[111, 9.99, true, false, "交个朋友", null]
// 数组嵌套,数组使用,用逗号分隔
[["张三", "李四", "王二", "麻子"],[111, 9.99, true, false, "兄弟们支持了吗?", null]
]
// 数组嵌套对象
[{"king": {"child": ["张三", "李四", "王二", "麻子"]}},[111, 9.99, true, false, "你好,陌生人", null]
]

三、cJSON详解

有了上面的知识,来看cJSON会发现,其实也很简单,没有那么难,只需要知道对应方法的含义和如何使用它,就能解决开发中遇到的问题了。

我们看cJSON数据结构如下

/* The cJSON structure: */
typedef struct cJSON
{struct cJSON *next;struct cJSON *prev;struct cJSON *child;int type;char *valuestring;/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */int valueint;double valuedouble;char *string;
} cJSON;

char *string:表示对象中的key
int type:用于描述数据元素的类型,type一共定义了 7种 类型。
如果获取的类型是:Number类型,使用valueint
如果获取的类型是:double类型,使用valuedouble
如果获取的类型是:string类型,使用valuestring

我们可以通过如下方法去检查type类型:

大家看一下,源码中,就是通过这种方式,去判断type类型,然后去获取最终的数据值的:

CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) 
{if (!cJSON_IsString(item)) {return NULL;}return item->valuestring;
}
...
CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item) 
{if (!cJSON_IsNumber(item)) {return NAN;}return item->valuedouble;
}

1、如何创建一个JSON对象?

带着问题去看源码并寻找解决答案

// cJSON.h
/* 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);

我们刚刚在上面介绍JSON的时候,知道JSON可以是如下几种类型的:

字符串、数字Number、NULL、BOOL、Json对象、Json数组

所以我们可以通过cJSON_Create... 来创建JSON对象。

那么创建完JSON对象之后,如何添加键值对呢?

// cJSON.h
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);

我们看下面这样的json应该如何使用cJSON?

{"pi": 3.141,"happy": true,"name": "头戴三叉束发紫金冠体挂西川红棉百花袍身披兽面吞头连环铠腰系勒甲玲珑狮蛮带手持方天画戟坐下嘶风赤兔马之吕小布是也"
}

使用方式:

int main()
{cJSON * root;// 创建根数据对象root=cJSON_CreateObject();// 添加键值对cJSON_AddBoolToObject(root,"happy",true);cJSON_AddNumberToObject(root,"pi",3.141);cJSON_AddNumberToObject(root,"name","头戴三叉束发紫金冠体挂西川红棉百花袍身披兽面吞头连环铠腰系勒甲玲珑狮蛮带手持方天画戟坐下嘶风赤兔马之吕小布是也"); // 将json形式转换成字符串char *out = cJSON_Print(root);printf("%s\n",out);// 释放内存,如果不删除会出现内存泄漏cJSON_Delete(root);  free(out);        
}

2、如何创建一个JSON数组?

看完上面的内容,我们应该知道应该用的是cJSON_CreateArray对吧。

假如我们有如下json内容:

[111, 9.99, true, false, "交个朋友", null]

使用方式:

int main()
{cJSON *root;root = cJSON_CreateArray();cJSON_AddItemToArray(root, cJSON_CreateNumber(111)); cJSON_AddItemToArray(root, cJSON_CreateNumber(9.99)); cJSON_AddItemToArray(root, cJSON_CreateBool(true));  cJSON_AddItemToArray(root, cJSON_CreateBool(false)); cJSON_AddItemToArray(root, cJSON_CreateString("交个朋友"));cJSON_AddItemToArray(root, cJSON_CreateNull());char *s = cJSON_PrintUnformatted(root);if(s){printf(" %s \n",s);free(s);}// 必须要删除,否则会出现内存泄漏cJSON_Delete(root);return 0;
}

3、如何创建一个JSON对象嵌套数组?

{"test":[{"name":"雷布斯","motto":"碉堡了,友商是傻瓜"}]
}

使用方式:

int main()
{cJSON *root, *body, *list;// json对象rootroot = cJSON_CreateObject();// root 添加键值对,test:json数组AcJSON_AddItemToObject(root,"test", body = cJSON_CreateArray());// json数组A,添加Json对象BcJSON_AddItemToArray(body, list = cJSON_CreateObject());// 在json对象B中添加键值对cJSON_AddStringToObject(list,"name","雷布斯");// 在json对象B中添加键值对cJSON_AddNumberToObject(list,"motto","碉堡了,友商是傻瓜");char *s = cJSON_PrintUnformatted(root);if(s){printf("%s \n",s);free(s);}if(root){// 必须要删除,否则会出现内存泄漏cJSON_Delete(root); }return 0;
}

4、如何解析json?

// cJSON.h
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);

将字符串转换为 cJSON 结构体

这里我们拿复杂的嵌套数据来讲解,json对象嵌套数组,如何解析呢?

{"list": [{"day": 1,"money": -1999999}, {"day": 10,"money": 1999999}]
}

我们看到,最外层是一个JSONObject
然后通过 key: list 获取JSONArray
JSONArray里面有2个JSONObject
然后通过 key: happykey: money 获取对应的值

int main()
{char *s = "{\"list\":[{\"day\":1,\"money\":-1999999},{\"day\":10,\"money\":1999999}]}";cJSON *root = cJSON_Parse(s);if(!root) {printf("cJSON_Parse失败 !\n");return -1;}cJSON *list = cJSON_GetObjectItem(root, "list");if(!list){printf("没有发现key为list的Item!\n");return -1;}// 这里我们需要获取数组的大小int array_size = cJSON_GetArraySize(list);printf("数组大小:%d\n",array_size);for(int i=0; i< array_size; i++) {// 获取JSONArraycJSON* item = cJSON_GetArrayItem(list, i);cJSON* day = cJSON_GetObjectItem(item, "day");printf("day is %d\n",day->valueint);cJSON* money = cJSON_GetObjectItem(item, "money");printf("money is %d\n",money->valueint);}if(root){// 删除JSON并释放内存cJSON_Delete(root);}return 0;
}

四、注意事项

刚刚上面我们介绍了,如何通过cJSON库:创建JSON以及如何解析JSON。

那么我们在cJSON解析数据的时候,一定要做数据健全性检查。

例如,我们刚写了下面2行代码:

cJSON *recvJson = cJSON_Parse(recvBuf);
cJSON *testID = cJSON_GetObjectItem(recvJson, "test_id");
...

我们这个时候能直接用testID吗? 肯定不能,我们需要检查一下它是否存在,可增加如下代码进行判断:

if(testID == NULL || testID->type == cJSON_NULL) 
{ printf("JSON数据有问题\r\n");
}
else 
{ // 这里做正常的业务处理...
}

这个时候可能有同学会疑问了,cJSON里面没有方法判断吗?

肯定有啊,请使用 cJSON_HasObjectItem

if(1 == cJSON_HasObjectItem(json,"test_id"))
{// 这里做正常的业务处理
}
else  
{printf("JSON数据有问题\r\n");
}

那么我们这个时候,假设使用的是 testID->valuestring 获取内容,需要判断是否和本地的一个字符串值 雷布斯 是否相等,我们应该如何做呢?

我们可以使用 strcmp 来比较2个数据值是否相等

if (strcmp(testIDValue, "雷布斯") == 0) 
{ // 这里判断2个数据值相等,这个分支里面写我们的业务代码...
}

相关文章:

OpenHarmony之cJSON库使用介绍

一、前言 我们前面OpenHarmony设备配网 文章中&#xff0c;给大家提供的示例有使用cJSON解析和cJSON创建json数据的用法 那么有同学会提出疑问&#xff0c;我难道只能用cJSON库&#xff1f; 当然不是啊&#xff0c;你也可以用 json-parser、parson、jansson 等等三方库 回到正题…...

门面设计模式

介绍 Java门面模式(Facade Pattern)是一种结构型设计模式,它提供了一个简单的接口,隐藏了复杂系统的实现细节,使得客户端可以更加容易地使用系统. 在Java门面模式中,一个门面对象(Facade)提供了一个简单的接口,该接口包装了一个或多个复杂的子系统,客户端可以直接使用门面对象…...

苹果手写笔好用吗?比较好用的ipad手写笔推荐

随着技术的进步&#xff0c;各种新型的电子产品和数码器件层出不穷。比如智能手机、IPAD、以及电容笔。而在实际生活中&#xff0c;为了更好的利用ipad&#xff0c;我们需要一支好用的电容笔。就好比如我们在ipad上做笔记&#xff0c;要用手来进行手写记录&#xff0c;会很不方…...

GPT-4来了!看看她究竟强在哪里!

GPT-4来了&#xff01;OpenAI老板Sam Altman直接开门见山地介绍说&#xff1a;这是我们迄今为止功能最强大的模型&#xff01;GPT-4是一个超大的多模态模型&#xff0c;也就是说&#xff0c;它的输入可以是文字&#xff08;上限2.5万字&#xff09;&#xff0c;还可以是图像。我…...

GPT-4 API 接口调用及价格分析

GPT-4 API 接口调用及价格分析 15日凌晨&#xff0c;OpenAI发布了万众期待的GPT-4&#xff01;新模型支持多模态&#xff0c;具备强大的识图能力&#xff0c;并且推理能力和回答准确性显著提高。在各种专业和学术基准测试上的表现都媲美甚至超过人类。难怪OpenAI CEO Sam Altm…...

MySQL高级功能:存储过程、触发器、事务、备份和恢复

MySQL高级功能MySQL是一款广泛使用的关系型数据库管理系统&#xff0c;它不仅具有基本的数据库功能&#xff0c;还支持一些高级功能&#xff0c;如存储过程、触发器、事务、备份和恢复等。这些高级功能可以帮助开发人员更高效地管理和维护数据库&#xff0c;本文将介绍MySQL的高…...

SAP 发出商品业务配置

SAP发出商品业务配置&#xff0c;即&#xff1a; 出具销售发票时结转成本 一、业务背景&#xff1a; 发出商品业务简单的理解为跨月开票&#xff0c;即出库与开票不在同一个月份。 该业务在系统内的实现方式&#xff0c;为保证成本与收入的配比&#xff0c;在出库时不计算成…...

C++线程池理解

线程池基本信息 线程池是一种结合池化思想衍生出来的一种线程管理及使用的方案 其主要针对服务器端多线程场景下&#xff0c;服务器频繁接收请求&#xff0c;每个请求都分配一个单独的线程去处理。 使用线程的开销&#xff1a; 创建和销毁线程调度线程 线程池主要解决的核…...

2023年最新软著申请流程(一):软件著作权说明、国家版权官网的账号注册与实名认证

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/129230460 红胖子(红模仿)的博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软…...

SuperMap iServer如何发布S3对象存储中的瓦片

作者&#xff1a;Carlo 前言&#xff1a; S3 对象存储服务是一个基于对象的海量存储服务&#xff0c;为客户提供海量、安全、高可靠、低成本的数据存储能力。其海量、安全的特性&#xff0c;为存储海量瓦片提供可能。 SuperMap iServer 支持将存储在阿里云对象存储 (OSS)、华为…...

ElasticSearch-第四天

目录 ElasticSearch文档分值_score计算底层原理 relevance score算法 Term frequency Inverse document frequency Field-length norm 分析一个document上的_score是如何被计算出来的 分词器工作流程 切分词语 内置分词器的介绍 定制分词器 ik分词器详解 IK分词器自…...

基于鲸鱼算法的极限学习机(ELM)分类算法-附代码

基于鲸鱼算法的极限学习机(ELM)分类算法 文章目录基于鲸鱼算法的极限学习机(ELM)分类算法1.极限学习机原理概述2.ELM学习算法3.分类问题4.基于鲸鱼算法优化的ELM5.测试结果6.参考文献7.Matlab代码摘要&#xff1a;本文利用鲸鱼算法对极限学习机进行优化&#xff0c;并用于分类问…...

一文彻底读懂webpack常用配置

开发环境 const webpack require("webpack"); const path require(path) module.exports {// entry: {// a: ./src/0706/a.js,// c: ./src/0706/c.js,// },entry: "./src/0707/reactDemo.js",output: {filename: [name]_dist.js,path: path.resolve(__…...

大环境不好,找工作太难?三面阿里,幸好做足了准备,已拿offer

三面大概九十分钟&#xff0c;问的东西很全面&#xff0c;需要做充足准备&#xff0c;就是除了概念以外问的有点懵逼了&#xff08;呜呜呜&#xff09;。回来之后把这些题目做了一个分类并整理出答案&#xff08;强迫症的我狂补知识&#xff09;分为软件测试基础、Python自动化…...

C++ 手撸简易服务器(完善版本)

本文没有带反射部分内容&#xff0c;可以看我之前发的 Server.h #pragma once#include <string> #include <iostream> #include <thread> #include <unordered_map> using namespace std; #ifndef _SERVER_ #define _SERVER_#include <winsock.h&…...

【Python入门第三十四天】Python丨文件处理

文件处理是任何 Web 应用程序的重要组成部分。 Python 有几个用于创建、读取、更新和删除文件的函数。 文件处理 在 Python 中使用文件的关键函数是 open() 函数。 open() 函数有两个参数&#xff1a;文件名和模式。 对于刚学Python的小伙伴&#xff0c;我给大家准备了2023…...

【Linux】写一个基础的bash

头文件#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/wait.h> #include<sys/stat.h> #include<string.h> #include<pwd.h> #include<dirent.h>分割输入的命令串字符串或参数内容为空则退出strtok( ,…...

图解如何一步步连接远程服务器——基于VScode

基于VScode连接远程服务器 安装Remote-SSH等插件 想要在vscode上连接远程服务器需要下载Remote-SSH系列插件&#xff1a; 直接在插件中搜索remote&#xff0c;即可找到&#xff0c;选择图片中的3个插件&#xff0c;点击install安装。 配置Remote-SSH 在这个步骤有多种操作…...

element - - - - - 你不知道的loading使用方式

求人不如求己 你不知道的loading使用方式1. 指令方式使用1.1 默认loading1.2 自定义loading1.3 整页加载2. 服务方式使用2.1 this.$loading的使用2.2 Loading.service的使用关于页面交互&#xff0c;最害怕的就是接口等待时间太长&#xff0c;用户体验不好。 而如何提高用户体…...

C++程序调用IsBadReadPtr或IsBadWritePtr引发内存访问违例问题的排查

目录 1、问题描述 2、VS中看不到有效的信息,尝试使用Windbg去分析 3、使用Windbg分析 4、最后...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

2.Vue编写一个app

1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)

题目 做法 启动靶机&#xff0c;点进去 点进去 查看URL&#xff0c;有 ?fileflag.php说明存在文件包含&#xff0c;原理是php://filter 协议 当它与包含函数结合时&#xff0c;php://filter流会被当作php文件执行。 用php://filter加编码&#xff0c;能让PHP把文件内容…...