一款輕量級的JSON解析庫,用cJSON讓你看清王者榮耀(2021第一篇部落格)
來源:微信公眾號「程式設計學習基地」
2021年的第一篇文章,帶你看清王者榮耀
JSON是一種輕量級的資料格式,應用廣泛。在C/C++應用中也常常作為配置檔案或者資料的儲存
JSON語法規則
JSON物件是一個無序的"名稱/值"鍵值對的集合:
- 以"
{
“開始,以”}
"結束,允許巢狀使用; - 每個名稱和值成對出現,名稱和值之間使用"
:
"分隔; - 鍵值對之間用"
,
"分隔 - 在這些字元前後允許存在無意義的空白符;
對於鍵值,可以有如下值:
- 一個新的json物件
- 陣列:使用"
[
“和”]
"表示 - 數字:直接表示,可以是整數,也可以是浮點數
- 字串:使用引號
"
表示 - 字面值:false、null、true中的一個(必須是小寫)
示例如下:
[{
"ename": 105,
"cname": "廉頗",
"title": "正義爆轟",
"new_type": 0,
"hero_type": 3,
"skin_name": "正義爆轟|地獄巖魂"
}, {
"ename": 106,
"cname": "小喬",
"title": "戀之微風",
"new_type": 0,
"hero_type": 2,
"skin_name": "戀之微風|萬聖前夜|天鵝之夢|純白花嫁|繽紛獨角獸"
}]
cJSON
cJSON下載使用
cJSON是使用ANSI C編寫的超輕量級的JSON解析器,因此在C中也常常是不二之選。
cJSON專案託管在Github上,倉庫地址如下:
https://github.com/DaveGamble/cJSON
使用Git命令將其拉取到本地:
git clone https://github.com/DaveGamble/cJSON.git
從Github拉取cJSON原始碼後,檔案非常多,但是其中cJSON的原始碼檔案只有兩個:
cJSON.h
cJSON.c
使用的時候,只需要將這兩個檔案複製到工程目錄,然後包含標頭檔案cJSON.h
即可,如下:
#include "cJSON.h"
詳細使用視訊:VS使用cJSON庫
關鍵資料結構
cJSON的關鍵資料結構如下:
typedef struct cJSON { //cJSON結構體
struct cJSON*next,*prev; /*後驅節點和前驅節點*/
struct cJSON *child; /*孩子節點*/
int type; /* 鍵的型別*/
char *valuestring; /*字串值*/
int valueint; /* 整數值*/
double valuedouble; /* 浮點數值*/
char *string; /* 鍵的名字*/
} cJSON;
json是一種組織良好的資料格式,因而JSON中的內容解析後,都可以通過以上資料結構進行處理。
例如,對於下面的json內容:
{
"name":"程式設計學習基地",
"site":"https://www.deroy.cn",
"age":1
}
解析後,site將會是name的next節點,並且它的鍵型別是字串。
cJSON資料解析
常用介面函式
用於將字串解析成json物件,若失敗則返回NULL。
cJSON *cJSON_Parse(const char *value);
用於獲取json物件中的某個節點,若失敗,返回NULL,成功則返回該節點物件。
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
用於釋放json物件相關記憶體。
void cJSON_Delete(cJSON *c);
如果JSON資料的值是陣列,可以通過下面介面獲取 JSON 陣列大小和陣列裡面的 JSON 物件
int cJSON_GetArraySize(const cJSON *array);
cJSON * cJSON_GetArrayItem(const cJSON *array, int index);
解析步驟
- 將JSON檔案內容讀取到buffer
- 通過cJSON介面解析buffer中的字串
- 獲取JSON指定欄位
為了將JSON檔案的內容讀取到buffer,需要知道檔案的大小:
size_t get_file_size(const char *filepath)
{
/*check input para*/
if(NULL == filepath)
return 0;
struct stat filestat;
memset(&filestat,0,sizeof(struct stat));
/*get file information*/
if(0 == stat(filepath,&filestat))
return filestat.st_size;
else
return 0;
}
然後申請一段記憶體,將檔案中的文字讀取到buffer中:
char *read_file_to_buf(const char *filepath)
{
/*check input para*/
if(NULL == filepath)
{
return NULL;
}
/*get file size*/
size_t size = get_file_size(filepath);
if(0 == size)
return NULL;
/*malloc memory*/
char *buf = malloc(size+1);
if(NULL == buf)
return NULL;
memset(buf,0,size+1);
/*read string from file*/
FILE *fp = fopen(filepath,"r");
size_t readSize = fread(buf,1,size,fp);
if(readSize != size)
{
/*read error*/
free(buf);
buf = NULL;
}
buf[size] = 0;
return buf;
}
再根據前面提到的解析流程,我們的JSON預解析函式如下:
cJSON *prepare_parse_json(const char *filePath)
{
/*check input para*/
if(NULL == filePath)
{
printf("input para is NULL\n");
return NULL;
}
/*read file content to buffer*/
char *buf = read_file_to_buf(filePath);
if(NULL == buf)
{
printf("read file to buf failed\n");
return NULL;
}
/*parse JSON*/
cJSON *pTemp = cJSON_Parse(buf);
free(buf);
buf = NULL;
return pTemp;
}
解析示例
#include<stdio.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<string.h>
#include"cJSON.h"
size_t get_file_size(const char *filepath)
{
/*check input para*/
if(NULL == filepath)
return 0;
struct stat filestat;
memset(&filestat,0,sizeof(struct stat));
/*get file information*/
if(0 == stat(filepath,&filestat))
return filestat.st_size;
else
return 0;
}
char *read_file_to_buf(const char *filepath)
{
/*check input para*/
if(NULL == filepath)
{
return NULL;
}
/*get file size*/
size_t size = get_file_size(filepath);
if(0 == size)
return NULL;
/*malloc memory*/
char *buf = malloc(size+1);
if(NULL == buf)
return NULL;
memset(buf,0,size+1);
/*read string from file*/
FILE *fp = fopen(filepath,"r");
size_t readSize = fread(buf,1,size,fp);
if(readSize != size)
{
/*read error*/
free(buf);
buf = NULL;
}
buf[size] = 0;
return buf;
}
/**/
cJSON *prepare_parse_json(const char *filePath)
{
/*check input para*/
if(NULL == filePath)
{
printf("input para is NULL\n");
return NULL;
}
/*read file content to buffer*/
char *buf = read_file_to_buf(filePath);
if(NULL == buf)
{
printf("read file to buf failed\n");
return NULL;
}
/*parse JSON*/
cJSON *pTemp = cJSON_Parse(buf);
free(buf);
buf = NULL;
return pTemp;
}
int main(void)
{
char *filename = "herolist.json";
cJSON *pJson = NULL;
cJSON *pTemp = NULL;
cJSON *pVal = NULL;
/*建立cJSON物件*/
pJson = prepare_parse_json(filename);
if(NULL == pJson)
{
printf("parse json failed\n");
return -1;
}
/*獲取cJSON陣列數量*/
int num = cJSON_GetArraySize(pJson);
/*遍歷每一個cJSON陣列元素*/
for(int index=0;index<num;index++)
{
/*獲取cJSON陣列中的第index個cJSON物件*/
pTemp = cJSON_GetArrayItem(pJson,index);
/*獲取cJSON物件中的key值為ename的物件*/
pVal = cJSON_GetObjectItem(pTemp,"ename");
printf("ename:%d\n",pVal->valueint);
pVal = cJSON_GetObjectItem(pTemp,"cname");
printf("cname:%s\n",pVal->valuestring);
pVal = cJSON_GetObjectItem(pTemp,"title");
printf("title:%s\n",pVal->valuestring);
pVal = cJSON_GetObjectItem(pTemp,"new_type");
printf("new_type:%d\n",pVal->valueint);
pVal = cJSON_GetObjectItem(pTemp,"hero_type");
printf("hero_type:%d\n",pVal->valueint);
pVal = cJSON_GetObjectItem(pTemp,"skin_name");
printf("skin_name:%s\n\n",pVal->valuestring);
printf("====================================\n\n");
}
/*釋放記憶體*/
cJSON_Delete(pJson);
pJson = NULL;
return 0;
}
gcc -o mian main.c cJSON.c
windows下VC6.0,VS也可以執行,但是因為編碼格式問題,我另寫了一套程式
為了讓輸出看起來舒服,改了點格式,輸出如下(刪減),原始碼獲取傳送關鍵字【王者榮耀】
|ename |cname |title |new_type |hero_type |skin_name|
-----------------------------------------------------------------------------------------------------------
|105 |廉頗 |正義爆轟 |0 |3 |正義爆轟|地獄巖魂|
-----------------------------------------------------------------------------------------------------------
|106 |小喬 |戀之微風 |0 |2 |戀之微風|萬聖前夜|天鵝之夢|純白花嫁|繽紛獨角獸|
-----------------------------------------------------------------------------------------------------------
|107 |趙雲 |蒼天翔龍 |0 |1 |蒼天翔龍|忍●炎影|未來紀元|皇家上將|嘻哈天王|白執事|引擎之心|
-----------------------------------------------------------------------------------------------------------
|108 |墨子 |和平守望 |0 |2 |和平守望|金屬風暴|龍騎士|進擊墨子號|
-----------------------------------------------------------------------------------------------------------
JSON資料封裝
封裝方法
封裝JSON資料的過程,其實就是建立連結串列和向連結串列中新增節點的過程。
首先來講述一下連結串列中的一些術語:
- 頭指標:指向連結串列頭結點的指標;
- 頭結點:不存放有效資料,方便連結串列操作;
- 首節點:第一個存放有效資料的節點;
- 尾節點:最後一個存放有效資料的節點;
封裝步驟
明白了這幾個概念之後,我們開始講述建立一段完整的JSON資料,即如何建立一條完整的連結串列。
- ① 建立頭指標:
cJSON* cjson_test = NULL;
- ② 建立頭結點,並將頭指標指向頭結點:
cjson_test = cJSON_CreateObject();
- ③ 盡情的向連結串列中新增節點:
/* 新增一個值為 null 的布林型別的JSON資料(新增一個連結串列節點) */
cJSON_AddNullToObject(cJSON * const object, const char * const name);
/* 新增一個值為 true 的布林型別的JSON資料(新增一個連結串列節點) */
cJSON_AddTrueToObject(cJSON * const object, const char * const name);
/* 新增一個值為 False 的布林型別的JSON資料(新增一個連結串列節點) */
cJSON_AddFalseToObject(cJSON * const object, const char * const name);
/* 新增一個值為布林型別的JSON資料 0:false 非0:true (新增一個連結串列節點) */
cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
/* 新增一條數值型別的JSON資料(新增一個連結串列節點) */
cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
/* 新增一條字串型別的JSON資料(新增一個連結串列節點) */
cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
/* 新增一行資料(新增一個連結串列節點) */
cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
/* 新增一個空物件(新增一個連結串列節點) */
cJSON_AddObjectToObject(cJSON * const object, const char * const name);
/* 新增一個空陣列(新增一個連結串列節點) */
cJSON_AddArrayToObject(cJSON * const object, const char * const name);
/* 新增一個巢狀的JSON物件/陣列(新增一個連結串列節點) */
cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
cJSON還提供了將JSON物件轉換成字串輸出到終端
char *cJSON_Print(const cJSON *item);
封裝示例
#include <stdio.h>
#include "cJSON.h"
int main(void)
{
cJSON* cjson_test = NULL;
cJSON* cjson_address = NULL;
cJSON* cjson_skill = NULL;
char* str = NULL;
/* 建立一個JSON資料物件(連結串列頭結點) */
cjson_test = cJSON_CreateObject();
/* 新增一個值為 null 的布林型別的JSON資料(新增一個連結串列節點) */
cJSON_AddNullToObject(cjson_test, "null_test");
/* 新增一個值為 true 的布林型別的JSON資料(新增一個連結串列節點) */
cJSON_AddTrueToObject(cjson_test,"true_test");
/* 新增一個值為 False 的布林型別的JSON資料(新增一個連結串列節點) */
cJSON_AddFalseToObject(cjson_test, "false_test");
/* 新增一個值為布林型別的JSON資料 0:false 非0:true (新增一個連結串列節點) */
cJSON_AddBoolToObject(cjson_test, "bool_test", 0);
/* 新增一條整數型別的JSON資料(新增一個連結串列節點) */
cJSON_AddNumberToObject(cjson_test, "int_test", 22);
/* 新增一條浮點型別的JSON資料(新增一個連結串列節點) */
cJSON_AddNumberToObject(cjson_test, "double_test", 55.5);
/* 新增一條字串型別的JSON資料(新增一個連結串列節點) */
cJSON_AddStringToObject(cjson_test, "str_test", "我是字串");
/* 新增一行任意資料(新增一個連結串列節點) */
cJSON_AddRawToObject(cjson_test, "key", "任意資料");
/* 新增一個空物件(新增一個連結串列節點) */
cJSON_AddObjectToObject(cjson_test, "objet");
/* 新增一個巢狀的JSON物件(新增一個連結串列節點) */
cjson_address = cJSON_CreateObject();
cJSON_AddStringToObject(cjson_address, "country", "China");
cJSON_AddNumberToObject(cjson_address, "zip-code", 111111);
cJSON_AddItemToObject(cjson_test, "address", cjson_address);
/* 新增一個空陣列(新增一個連結串列節點) */
cJSON_AddArrayToObject(cjson_test, "Array");
/* 新增一個陣列型別的JSON資料(新增一個連結串列節點) */
cjson_skill = cJSON_CreateArray();
cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "C" ));
cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "C++" ));
cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "Python" ));
cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "Java"));
cJSON_AddItemToObject(cjson_test, "skill", cjson_skill);
/* 列印JSON物件(整條連結串列)的所有資料 */
str = cJSON_Print(cjson_test);
printf("%s\n", str);
return 0;
}
輸出結果:
{
"null_test": null,
"true_test": true,
"false_test": false,
"bool_test": false,
"int_test": 22,
"double_test": 55.5,
"str_test": "我是字串",
"key": 任意資料,
"objet": {
},
"address": {
"country": "China",
"zip-code": 111111
},
"Array": [],
"skill": ["C", "C++", "Python", "Java"]
}
完整程式碼:
連結:https://pan.baidu.com/s/1Pej2aKKPW5d0_cmUMgm5HQ
提取碼:18re
相關文章
- cJSON:解析JSONJSON
- 王者榮耀墨子技能解析與使用技巧,王者榮耀墨子大招使用技巧
- 使用cJSON庫對JSON格式進行解析JSON
- 王者榮耀李白該怎麼出裝?王者榮耀李白出裝及順序解析
- 王者榮耀鍾馗閃現技能怎麼用?王者榮耀鍾馗技能的玩法技巧
- 深度解析國內首個雲原生資料庫POLARDB的“王者榮耀”資料庫
- Spring Boot搭建輕量級的部落格系統Spring Boot
- 年輕人的第一篇部落格
- 王者榮耀「冰山下」
- 王者榮耀鍾馗技能怎麼用?王者榮耀鍾馗連招怎麼連呢?
- 是什麼讓《王者榮耀》長盛不衰,成為一款火爆的國民遊戲?遊戲
- 王者榮耀嫦娥打野出裝五級銘文搭配推薦,王者榮耀嫦娥打野怎麼出裝?
- 《王者榮耀》:屬於自己的路
- 推薦一款輕量級堡壘機系統讓你防護“rm -rf 刪庫跑路”
- 開發有新意的短視訊,你就是榮耀王者
- 王者榮耀羋月的玩法技巧 王者榮耀線霸羋月如何自爆一路?
- 王者榮耀助手升級為《王者營地》 新版核心功能有哪些?
- 王者榮耀明世隱怎麼玩?王者榮耀明世隱出裝順序和五級銘文推薦
- 王者榮耀盾山要怎麼剋制呢?王者榮耀盾山的剋制方法攻略
- 王者榮耀小喬怎麼玩?王者榮耀小喬技能介紹和玩法攻略
- 王者榮耀“吃雞模式”玩法介紹 王者榮耀邊境突圍怎麼玩模式
- 2018王者榮耀KPL秋季賽賽程表 2018王者榮耀KPL秋季賽賽制
- 不可不知的JSON處理庫(cJSON)JSON
- 我和《王者榮耀》的48小時
- 吃雞、王者榮耀都在用的使用者行為模型,1個公式幫你輕鬆拆解模型公式
- 王者榮耀什麼英雄剋制嫦娥?王者榮耀這幾個英雄可以剋制嫦娥
- 比MySQL快6倍 深度解析國內首個雲原生資料庫POLARDB的“王者榮耀”MySql資料庫
- 比MySQL快6倍深度解析國內首個雲原生資料庫POLARDB的“王者榮耀”MySql資料庫
- 王者榮耀安琪拉技能詳解析,安琪拉技能效果到底是怎樣的?
- 王者榮耀S14呂布玩法解析:新版呂布五級銘文搭配推薦
- 王者榮耀剋制米萊狄的英雄有哪些?王者榮耀剋制米萊狄的英雄介紹
- 王者榮耀怎麼賺錢(一)
- python爬取王者榮耀皮膚Python
- 張一鳴尋找“王者榮耀”
- cJSON:構建JSONJSON
- 王者榮耀米萊狄出裝和銘文搭配 王者榮耀米萊狄技能介紹
- OPPO R15王者榮耀體驗評測 OPPO R15玩王者榮耀卡嗎?
- sal原始碼解析-輕量級的滾動動畫庫原始碼動畫