目前考虑需使用C++操作JSON串,避免重复造轮子,GitHub上有不少开源好使的C++ JSON库。如jsoncpp、frozen 、JSON++ 、JeayeSON、PicoJSON等等,经过对比分析,发现“jsoncpp”是一个应用比较广、开源、轻量级的json库,也不乏各类学习资料,参与维护者多,如果存在bug时也能及时发现。
jsoncpp 源码:
https://github.com/open-source-parsers/jsoncpp
https://sourceforge.net/projects/jsoncpp/postdownload
jsoncpp使用也比较容易上手,网络上也不少教程,以下文章要参考各大网络博客总结完成。jsoncpp主要包括三个类(class),Value、Reader、Writer,对应于三个json_value.cpp、json_write.cpp、json_read.cpp及对应的头文件。
1.Value 类
Value类是jsoncpp最基本的也是最常用的类,用于创建JSON串对象、对象赋值、对象交换、JSON大小比较、键值赋值等。
1.1 创建对象/键值和赋值
Json::Value root; /* 创建json对象 */
root["Name"] = Json::Value("Acuity"); /* 新建一个键值, 赋值 字符串 */
root["Increase"] = Json::Value(180); /* 新建一个键值,赋值数字 */
root["Array"].append("string0"); /* 新建一个数组键值,对第一个元素赋值 */
root["Array"].append(23); /* 对数组键值第二个元素赋值 */
1.2 获取对象类型
Json::ValueType type = root.type(); /* 获得 root 的类型 */
1.3 判断Key是否存在
bool Json::Value::isMember ( const char * key) const
1.4 检查Value类型,如null、bool、array等
bool isNull() const;
bool isBool() const;
bool isInt() const;
bool isInt64() const;
bool isUInt() const;
bool isUInt64() const;
bool isIntegral() const;
bool isDouble() const;
bool isNumeric() const;
bool isString() const;
bool isArray() const;
bool isObject() const;
1.5 获取所有Key
Members getMemberNames() const;
Members原型为:typedef std::vector
即是一个值为string的vector,通过getMemberNames得到所有的key。
1.6 删除成员
Value Json::Value::removeMember( const char* key)
2.Reader类
Json::Reader 主要功能是将JSON字符解析为 jsoncpp的Json::Value 对象。
Json::Reader reader;
Json::Value root;
const char* json_str = "{\"Year\" : 2019,\"Mon\":7}";
if (reader.parse(json_str , root))
{
std::cout << root["Year"] << std::endl;
std::cout << root["Mon"] << std::endl;
}
3.Writer类
Json::Writer 类是把Json::Value对象写到string对象中。需要注意的是,Json::Writer是个抽象纯虚类,只作为父类继承,不能调用;其被两个子类Json::FastWriter和Json::StyledWriter继承。 两个子类功能差异是,FastWriter就是无格式的写入,所以比较“快”,但这样的JSON串看起来很乱没有格式;而StyledWriter是带有缩进、排版等格式的写入,牺牲一定的效率,使得比较方便用户阅读(友好)。
(网络)传输过程的JSON串通常使用的是“FastWriter”格式。
Json::FastWriter fw;
std::cout << fw.write(root) << std::endl;
Json::StyledWriter sw;
std::cout << sw.write(root) << std::endl;
4.应用例程
4.1 jsoncpp库编译
目前jsoncpp最新版本是1.8.4,该版本需C++11以上的编译器支持。由于本人Linux环境比较旧,所以下载的是0.5.0的版本。后续再搭建1.8.4版本环境。使用过程遇到小插曲,本来想直接将源码拷贝到工程下编译,经过一番折腾还是编译不过,不知道啥回事。后面只能将jsoncpp编译成库文件,然后使用。当然,实际使用也建议编译成库文件(静态库/动态库),方便项目的拓展。
编译命令:
tar -zxvf jsoncpp-src-0.5.0.tar.gz
cd jsoncpp-src-0.5.0
scons platform=linux-gcc
在“/libs/linux-gcc-4.4.3”目录下生成静态库和动态库文件,名字后面接着编译器(gcc)版本。
4. 2 编写测试例程
#include
#include
#include "../include/json/json.h" /* 暂用绝对路径,用相对路径出错,Makefile指定路径依然出错 */
using namespace std;
/* JSON字符串 */
const char *js_info ={ \
"{ \
\"Year\": 2019, \
\"Mon\": 6, \
\"Week\":[ \
\"Sunday\", \"Monday\"], \
\"People\":{ \
\"Name\":\"Acuity\", \
\"Increase\":180, \
\"English name\":null, \
\"Crime\":false, \
} \
}"
};
/* Json::Reader 类 */
void js_read(void)
{
Json::Value root;
Json::Reader reader;
if(reader.parse(js_info,root))
{
printf("parse failed\r\n");
return;
}
std::cout << "Reader Parse json string:" << std::endl;
std::cout << root["Year"] << std::endl;
std::cout << root["Week"] << std::endl;
std::cout << root["People"] << std::endl;
}
/* Json::Writer 类 */
void js_write(void)
{
Json::Value root;
Json::Value people;
Json::FastWriter fw;
Json::StyledWriter sw;
root["Year"] = "2019";
root["Mon"] = Json::Value("6");
root["Week"].append("Sunday");
root["Week"].append("Monday");
people["Name"] = "Acuity";
people["Increase"] = "180";
root["People"] = people; /* 对象嵌套 */
/* 调用Json::FastWriter格式JSON串 */
cout << "Json::FastWriter:" << endl;
cout << fw.write(root) << endl;
/* 调用Json::StyledWriter格式JSON串 */
cout << "Json::StyledWriter:" << endl;
cout << sw.write(root) << endl;
/* 输出到文件 */
ofstream fd;
fd.open("js_test.json");
fd << sw.write(root);
fd.close();
}
void js_other(void)
{
Json::Value root;
Json::Reader reader;
if(reader.parse(js_info,root))
{
printf("parse failed\r\n");
return;
}
if(root.isMember("Year"))
std::cout<<"Year is a member"<
4. 3 Makefile
这里采用的是静态链接库的链接方式,方便运行测试。如用动态链接,需拷贝动态库到环境变量目录下或者软链接到当前库文件目录。
VERSION =
CC =g++
DEBUG =
CFLAGS =-Wall -c
SOURCES =$(wildcard ./src/*.cpp)
INCLUDES =-I./include/json
LIB_NAMES =-ljson_linux-gcc-4.4.3_libmt
LIB_PATH =-L./jsonlib
OBJ =$(patsubst %.cpp, %.o, $(SOURCES))
TARGET =js-test
#links
$(TARGET):$(OBJ)
@mkdir -p output
$(CC) $(OBJ) $(LIB_PATH) $(LIB_NAMES) -o output/$(TARGET)$(VERSION)
@rm -rf $(OBJ)
#compile
%.o: %.c
$(CC) $(INCLUDES) $(DEBUG) $(CFLAGS) $^ -o $@
.PHONY:clean
clean:
@echo "Remove linked and compiled files......"
rm -rf $(OBJ) $(TARGET) output