在 C++ 中读取 json 个文件
Reading json files in C++
我正在尝试读取 JSON 文件。到目前为止,我一直专注于使用 jsoncpp
库。但是,文档对我来说很难理解。任何人都可以通俗地解释它的作用吗?
假设我有一个 people.json
看起来像这样:
{"Anna" : {
"age": 18,
"profession": "student"},
"Ben" : {
"age" : "nineteen",
"profession": "mechanic"}
}
当我读入时会发生什么?我可以创建某种数据结构 people
,我可以通过 Anna
和 Ben
以及 age
和 profession
对其进行索引吗? people
的数据类型是什么?我认为它类似于(嵌套)地图,但地图值始终必须具有相同的类型,不是吗?
我之前使用过 python,我的 "goal"(对于 C++ 可能设置不当)是为了获得嵌套 python 字典的等价物。
是的,您可以创建一个嵌套数据结构 people
,它可以被 Anna
和 Ben
索引。但是,您不能直接通过 age
和 profession
对其进行索引(我将在代码中找到这部分)。
people
的数据类型是Json::Value
类型(在jsoncpp中定义)。没错,它类似于嵌套映射,但是 Value
是一种数据结构,它被定义为可以存储和访问多种类型。它类似于以 string
为键,以 Json::Value
为值的映射。它也可以是 unsigned int
作为键和 Json::Value
作为值之间的映射(在 json 数组的情况下)。
代码如下:
#include <json/value.h>
#include <fstream>
std::ifstream people_file("people.json", std::ifstream::binary);
people_file >> people;
cout<<people; //This will print the entire json object.
//The following lines will let you access the indexed objects.
cout<<people["Anna"]; //Prints the value for "Anna"
cout<<people["ben"]; //Prints the value for "Ben"
cout<<people["Anna"]["profession"]; //Prints the value corresponding to "profession" in the json for "Anna"
cout<<people["profession"]; //NULL! There is no element with key "profession". Hence a new empty element will be created.
如您所见,您可以仅根据输入数据的层次结构为 json 对象编制索引。
看看nlohmann's JSON Repository on GitHub。我发现这是使用 JSON.
最方便的方法
它的设计就像一个 STL 容器,这使得它的使用非常直观。
本质上,javascript 和 C++ 基于两个不同的原则工作。 Javascript 创建一个 "associative array" 或散列 table,它将字符串键(字段名称)与值匹配。 C++ 在内存中布局结构,所以前 4 个字节是一个整数,这是一个年龄,然后我们可能有一个固定的 32 字节字符串,代表 "profession".
所以 javascript 将处理诸如 "age" 在一条记录中为 18 而在另一条记录中为 "nineteen" 之类的事情。 C++ 不能。 (但是 C++ 快得多)。
所以如果我们想在 C++ 中处理 JSON,我们必须从头开始构建关联数组。然后我们必须用它们的类型标记值。它是整数、实数值(可能 return 为 "double")、布尔值、字符串吗?因此 JSON C++ class 是相当大的代码块。实际上,我们正在做的是用 C++ 实现一些 javascript 引擎。然后我们将 JSON 作为字符串传递给我们的 JSON 解析器,并将其标记化,并为我们提供从 C++ 查询 JSON 的函数。
像这样存储人
{"Anna" : {
"age": 18,
"profession": "student"},
"Ben" : {
"age" : "nineteen",
"profession": "mechanic"}
}
会引起问题,特别是如果不同的人有相同的名字..
而是像这样使用数组存储对象
{
"peoples":[
{
"name":"Anna",
"age": 18,
"profession": "student"
},
{
"name":"Ben",
"age" : "nineteen",
"profession": "mechanic"
}
]
}
这样,您可以枚举对象,或者通过数字索引访问对象。
请记住 json 是存储结构,而不是动态排序器或索引器。
使用存储在 json 中的数据根据需要构建索引并访问数据。
读取json配置文件的示例(带有完整源代码):
https://github.com/sksodhi/CodeNuggets/tree/master/json/config_read
> pwd
/root/CodeNuggets/json/config_read
> ls
Makefile README.md ReadJsonCfg.cpp cfg.json
> cat cfg.json
{
"Note" : "This is a cofiguration file",
"Config" : {
"server-ip" : "10.10.10.20",
"server-port" : "5555",
"buffer-length" : 5000
}
}
> cat ReadJsonCfg.cpp
#include <iostream>
#include <json/value.h>
#include <jsoncpp/json/json.h>
#include <fstream>
void
displayCfg(const Json::Value &cfg_root);
int
main()
{
Json::Reader reader;
Json::Value cfg_root;
std::ifstream cfgfile("cfg.json");
cfgfile >> cfg_root;
std::cout << "______ cfg_root : start ______" << std::endl;
std::cout << cfg_root << std::endl;
std::cout << "______ cfg_root : end ________" << std::endl;
displayCfg(cfg_root);
}
void
displayCfg(const Json::Value &cfg_root)
{
std::string serverIP = cfg_root["Config"]["server-ip"].asString();
std::string serverPort = cfg_root["Config"]["server-port"].asString();
unsigned int bufferLen = cfg_root["Config"]["buffer-length"].asUInt();
std::cout << "______ Configuration ______" << std::endl;
std::cout << "server-ip :" << serverIP << std::endl;
std::cout << "server-port :" << serverPort << std::endl;
std::cout << "buffer-length :" << bufferLen<< std::endl;
}
> cat Makefile
CXX = g++
PROG = readjsoncfg
CXXFLAGS += -g -O0 -std=c++11
CPPFLAGS += \
-I. \
-I/usr/include/jsoncpp
LDLIBS = \
-ljsoncpp
LDFLAGS += -L/usr/local/lib $(LDLIBS)
all: $(PROG)
@echo $(PROG) compilation success!
SRCS = \
ReadJsonCfg.cpp
OBJS=$(subst .cc,.o, $(subst .cpp,.o, $(SRCS)))
$(PROG): $(OBJS)
$(CXX) $^ $(LDFLAGS) -o $@
clean:
rm -f $(OBJS) $(PROG) ./.depend
depend: .depend
.depend: $(SRCS)
rm -f ./.depend
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -MM $^ > ./.depend;
include .depend
> make
Makefile:43: .depend: No such file or directory
rm -f ./.depend
g++ -g -O0 -std=c++11 -I. -I/usr/include/jsoncpp -MM ReadJsonCfg.cpp > ./.depend;
g++ -g -O0 -std=c++11 -I. -I/usr/include/jsoncpp -c -o ReadJsonCfg.o ReadJsonCfg.cpp
g++ ReadJsonCfg.o -L/usr/local/lib -ljsoncpp -o readjsoncfg
readjsoncfg compilation success!
> ./readjsoncfg
______ cfg_root : start ______
{
"Config" :
{
"buffer-length" : 5000,
"server-ip" : "10.10.10.20",
"server-port" : "5555"
},
"Note" : "This is a cofiguration file"
}
______ cfg_root : end ________
______ Configuration ______
server-ip :10.10.10.20
server-port :5555
buffer-length :5000
>
这是另一种更容易阅读的 json 文件:
#include "json/json.h"
std::ifstream file_input("input.json");
Json::Reader reader;
Json::Value root;
reader.parse(file_input, root);
cout << root;
然后您可以获得这样的值:
cout << root["key"]
您可以使用 c++ boost::property_tree::ptree 来解析 json 数据。这是您的 json 数据的示例。如果您在每个子节点内移动名称,这会更容易
#include <iostream>
#include <string>
#include <tuple>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
int main () {
namespace pt = boost::property_tree;
pt::ptree loadPtreeRoot;
pt::read_json("example.json", loadPtreeRoot);
std::vector<std::tuple<std::string, std::string, std::string>> people;
pt::ptree temp ;
pt::ptree tage ;
pt::ptree tprofession ;
std::string age ;
std::string profession ;
//Get first child
temp = loadPtreeRoot.get_child("Anna");
tage = temp.get_child("age");
tprofession = temp.get_child("profession");
age = tage.get_value<std::string>();
profession = tprofession.get_value<std::string>();
std::cout << "age: " << age << "\n" << "profession :" << profession << "\n" ;
//push tuple to vector
people.push_back(std::make_tuple("Anna", age, profession));
//Get Second child
temp = loadPtreeRoot.get_child("Ben");
tage = temp.get_child("age");
tprofession = temp.get_child("profession");
age = tage.get_value<std::string>();
profession = tprofession.get_value<std::string>();
std::cout << "age: " << age << "\n" << "profession :" << profession << "\n" ;
//push tuple to vector
people.push_back(std::make_tuple("Ben", age, profession));
for (const auto& tmppeople: people) {
std::cout << "Child[" << std::get<0>(tmppeople) << "] = " << " age : "
<< std::get<1>(tmppeople) << "\n profession : " << std::get<2>(tmppeople) << "\n";
}
}
fedora 33 的完整最小工作示例
使用 sudo dnf install jsoncpp-devel
获取库。
将以下文件存储在您的项目文件夹中:
people.json
{
"Anna":
{
"age": 18,
"profession": "student"
},
"Ben":
{
"age" : "nineteen",
"profession": "mechanic"
}
}
main.cpp
#include <iostream>
#include <fstream>
#include <json/json.h>
int main()
{
Json::Value people;
std::ifstream people_file("people.json", std::ifstream::binary);
people_file >> people;
std::cout << people["Anna"] << "\n";
std::cout << people["Anna"]["profession"] << "\n";
}
用 g++ -ljsoncpp main.cpp
编译。调用 ./a.out
会产生
输出
{
"age" : 18,
"profession" : "student"
}
"student"
我正在尝试读取 JSON 文件。到目前为止,我一直专注于使用 jsoncpp
库。但是,文档对我来说很难理解。任何人都可以通俗地解释它的作用吗?
假设我有一个 people.json
看起来像这样:
{"Anna" : {
"age": 18,
"profession": "student"},
"Ben" : {
"age" : "nineteen",
"profession": "mechanic"}
}
当我读入时会发生什么?我可以创建某种数据结构 people
,我可以通过 Anna
和 Ben
以及 age
和 profession
对其进行索引吗? people
的数据类型是什么?我认为它类似于(嵌套)地图,但地图值始终必须具有相同的类型,不是吗?
我之前使用过 python,我的 "goal"(对于 C++ 可能设置不当)是为了获得嵌套 python 字典的等价物。
是的,您可以创建一个嵌套数据结构
people
,它可以被Anna
和Ben
索引。但是,您不能直接通过age
和profession
对其进行索引(我将在代码中找到这部分)。people
的数据类型是Json::Value
类型(在jsoncpp中定义)。没错,它类似于嵌套映射,但是Value
是一种数据结构,它被定义为可以存储和访问多种类型。它类似于以string
为键,以Json::Value
为值的映射。它也可以是unsigned int
作为键和Json::Value
作为值之间的映射(在 json 数组的情况下)。
代码如下:
#include <json/value.h>
#include <fstream>
std::ifstream people_file("people.json", std::ifstream::binary);
people_file >> people;
cout<<people; //This will print the entire json object.
//The following lines will let you access the indexed objects.
cout<<people["Anna"]; //Prints the value for "Anna"
cout<<people["ben"]; //Prints the value for "Ben"
cout<<people["Anna"]["profession"]; //Prints the value corresponding to "profession" in the json for "Anna"
cout<<people["profession"]; //NULL! There is no element with key "profession". Hence a new empty element will be created.
如您所见,您可以仅根据输入数据的层次结构为 json 对象编制索引。
看看nlohmann's JSON Repository on GitHub。我发现这是使用 JSON.
最方便的方法它的设计就像一个 STL 容器,这使得它的使用非常直观。
本质上,javascript 和 C++ 基于两个不同的原则工作。 Javascript 创建一个 "associative array" 或散列 table,它将字符串键(字段名称)与值匹配。 C++ 在内存中布局结构,所以前 4 个字节是一个整数,这是一个年龄,然后我们可能有一个固定的 32 字节字符串,代表 "profession".
所以 javascript 将处理诸如 "age" 在一条记录中为 18 而在另一条记录中为 "nineteen" 之类的事情。 C++ 不能。 (但是 C++ 快得多)。
所以如果我们想在 C++ 中处理 JSON,我们必须从头开始构建关联数组。然后我们必须用它们的类型标记值。它是整数、实数值(可能 return 为 "double")、布尔值、字符串吗?因此 JSON C++ class 是相当大的代码块。实际上,我们正在做的是用 C++ 实现一些 javascript 引擎。然后我们将 JSON 作为字符串传递给我们的 JSON 解析器,并将其标记化,并为我们提供从 C++ 查询 JSON 的函数。
像这样存储人
{"Anna" : {
"age": 18,
"profession": "student"},
"Ben" : {
"age" : "nineteen",
"profession": "mechanic"}
}
会引起问题,特别是如果不同的人有相同的名字..
而是像这样使用数组存储对象
{
"peoples":[
{
"name":"Anna",
"age": 18,
"profession": "student"
},
{
"name":"Ben",
"age" : "nineteen",
"profession": "mechanic"
}
]
}
这样,您可以枚举对象,或者通过数字索引访问对象。 请记住 json 是存储结构,而不是动态排序器或索引器。 使用存储在 json 中的数据根据需要构建索引并访问数据。
读取json配置文件的示例(带有完整源代码):
https://github.com/sksodhi/CodeNuggets/tree/master/json/config_read
> pwd
/root/CodeNuggets/json/config_read
> ls
Makefile README.md ReadJsonCfg.cpp cfg.json
> cat cfg.json
{
"Note" : "This is a cofiguration file",
"Config" : {
"server-ip" : "10.10.10.20",
"server-port" : "5555",
"buffer-length" : 5000
}
}
> cat ReadJsonCfg.cpp
#include <iostream>
#include <json/value.h>
#include <jsoncpp/json/json.h>
#include <fstream>
void
displayCfg(const Json::Value &cfg_root);
int
main()
{
Json::Reader reader;
Json::Value cfg_root;
std::ifstream cfgfile("cfg.json");
cfgfile >> cfg_root;
std::cout << "______ cfg_root : start ______" << std::endl;
std::cout << cfg_root << std::endl;
std::cout << "______ cfg_root : end ________" << std::endl;
displayCfg(cfg_root);
}
void
displayCfg(const Json::Value &cfg_root)
{
std::string serverIP = cfg_root["Config"]["server-ip"].asString();
std::string serverPort = cfg_root["Config"]["server-port"].asString();
unsigned int bufferLen = cfg_root["Config"]["buffer-length"].asUInt();
std::cout << "______ Configuration ______" << std::endl;
std::cout << "server-ip :" << serverIP << std::endl;
std::cout << "server-port :" << serverPort << std::endl;
std::cout << "buffer-length :" << bufferLen<< std::endl;
}
> cat Makefile
CXX = g++
PROG = readjsoncfg
CXXFLAGS += -g -O0 -std=c++11
CPPFLAGS += \
-I. \
-I/usr/include/jsoncpp
LDLIBS = \
-ljsoncpp
LDFLAGS += -L/usr/local/lib $(LDLIBS)
all: $(PROG)
@echo $(PROG) compilation success!
SRCS = \
ReadJsonCfg.cpp
OBJS=$(subst .cc,.o, $(subst .cpp,.o, $(SRCS)))
$(PROG): $(OBJS)
$(CXX) $^ $(LDFLAGS) -o $@
clean:
rm -f $(OBJS) $(PROG) ./.depend
depend: .depend
.depend: $(SRCS)
rm -f ./.depend
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -MM $^ > ./.depend;
include .depend
> make
Makefile:43: .depend: No such file or directory
rm -f ./.depend
g++ -g -O0 -std=c++11 -I. -I/usr/include/jsoncpp -MM ReadJsonCfg.cpp > ./.depend;
g++ -g -O0 -std=c++11 -I. -I/usr/include/jsoncpp -c -o ReadJsonCfg.o ReadJsonCfg.cpp
g++ ReadJsonCfg.o -L/usr/local/lib -ljsoncpp -o readjsoncfg
readjsoncfg compilation success!
> ./readjsoncfg
______ cfg_root : start ______
{
"Config" :
{
"buffer-length" : 5000,
"server-ip" : "10.10.10.20",
"server-port" : "5555"
},
"Note" : "This is a cofiguration file"
}
______ cfg_root : end ________
______ Configuration ______
server-ip :10.10.10.20
server-port :5555
buffer-length :5000
>
这是另一种更容易阅读的 json 文件:
#include "json/json.h"
std::ifstream file_input("input.json");
Json::Reader reader;
Json::Value root;
reader.parse(file_input, root);
cout << root;
然后您可以获得这样的值:
cout << root["key"]
您可以使用 c++ boost::property_tree::ptree 来解析 json 数据。这是您的 json 数据的示例。如果您在每个子节点内移动名称,这会更容易
#include <iostream>
#include <string>
#include <tuple>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
int main () {
namespace pt = boost::property_tree;
pt::ptree loadPtreeRoot;
pt::read_json("example.json", loadPtreeRoot);
std::vector<std::tuple<std::string, std::string, std::string>> people;
pt::ptree temp ;
pt::ptree tage ;
pt::ptree tprofession ;
std::string age ;
std::string profession ;
//Get first child
temp = loadPtreeRoot.get_child("Anna");
tage = temp.get_child("age");
tprofession = temp.get_child("profession");
age = tage.get_value<std::string>();
profession = tprofession.get_value<std::string>();
std::cout << "age: " << age << "\n" << "profession :" << profession << "\n" ;
//push tuple to vector
people.push_back(std::make_tuple("Anna", age, profession));
//Get Second child
temp = loadPtreeRoot.get_child("Ben");
tage = temp.get_child("age");
tprofession = temp.get_child("profession");
age = tage.get_value<std::string>();
profession = tprofession.get_value<std::string>();
std::cout << "age: " << age << "\n" << "profession :" << profession << "\n" ;
//push tuple to vector
people.push_back(std::make_tuple("Ben", age, profession));
for (const auto& tmppeople: people) {
std::cout << "Child[" << std::get<0>(tmppeople) << "] = " << " age : "
<< std::get<1>(tmppeople) << "\n profession : " << std::get<2>(tmppeople) << "\n";
}
}
fedora 33 的完整最小工作示例
使用 sudo dnf install jsoncpp-devel
获取库。
将以下文件存储在您的项目文件夹中:
people.json
{
"Anna":
{
"age": 18,
"profession": "student"
},
"Ben":
{
"age" : "nineteen",
"profession": "mechanic"
}
}
main.cpp
#include <iostream>
#include <fstream>
#include <json/json.h>
int main()
{
Json::Value people;
std::ifstream people_file("people.json", std::ifstream::binary);
people_file >> people;
std::cout << people["Anna"] << "\n";
std::cout << people["Anna"]["profession"] << "\n";
}
用 g++ -ljsoncpp main.cpp
编译。调用 ./a.out
会产生
输出
{
"age" : 18,
"profession" : "student"
}
"student"