Чтение json файлов в С++
Я пытаюсь прочитать в файле JSON. До сих пор я сосредоточился на использовании библиотеки jsoncpp
. Однако документация для меня довольно сложна для понимания. Может ли кто-нибудь объяснить непрофессионалом, что он делает?
Скажем, у меня есть people.json
который выглядит так:
{"Anna" : {
"age": 18,
"profession": "student"},
"Ben" : {
"age" : "nineteen",
"profession": "mechanic"}
}
Что происходит, когда я читаю это? Могу ли я создать некую структуру данных people
которую я могу индексировать по Anna
и Ben
а также по age
и profession
? Какой тип данных people
? Я думал, что это будет что-то похожее на (вложенную) карту, но значения карты всегда должны иметь один и тот же тип, не так ли?
Я работал с Python раньше, и моя "цель" (которая может быть неправильно поставлена для C++) - получить эквивалент вложенного словаря Python.
Ответы
Ответ 1
-
Да, вы можете создать вложенную структуру данных 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-объект только на основе иерархии входных данных.
Ответ 2
Взгляните на репозиторий nlohmann JSON на GitHub. Я обнаружил, что это наиболее удобный способ работы с JSON.
Он разработан, чтобы вести себя так же, как контейнер STL, что делает его использование очень интуитивно понятным.
Ответ 3
Практически javascript и С++ работают на двух разных принципах. Javascript создает "ассоциативный массив" или хеш-таблицу, которая соответствует строковому ключу, который является именем поля, к значению. С++ выделяет структуры в памяти, поэтому первые 4 байта представляют собой целое число, которое представляет собой возраст, тогда, возможно, у нас есть фиксированная строка с байтом длиной 32 байта, которая представляет "профессию".
Таким образом, javascript будет обрабатывать такие вещи, как "возраст", равный 18 в одной записи и "девятнадцать" в другой. С++ не может. (Однако С++ намного быстрее).
Итак, если мы хотим обрабатывать JSON в С++, нам нужно построить ассоциативный массив с нуля. Затем мы должны пометить значения их типами. Является ли это целым числом, реальным значением (возможно, возвращаемым как "double" ), boolean, string? Из этого следует, что класс JSON С++ представляет собой довольно большой фрагмент кода. Эффективно то, что мы делаем, это реализовать немного механизма javascript на С++. Затем мы передаем JSON-синтаксический анализатор JSON как строку, и он его подделывает, и дает нам функции для запроса JSON из С++.
Ответ 4
Пример (с полным исходным кодом) для чтения конфигурационного файла 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 [email protected]
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
>
Ответ 5
Вот еще одна более простая возможность прочитать в файле 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"]
Ответ 6
хранение таких людей
{"Anna" : {
"age": 18,
"profession": "student"},
"Ben" : {
"age" : "nineteen",
"profession": "mechanic"}
}
вызовет проблемы, особенно если разные люди имеют одно и то же имя.
скорее использовать массив, хранящий объекты, подобные этому
{
"peoples":[
{
"name":"Anna",
"age": 18,
"profession": "student"
},
{
"name":"Ben",
"age" : "nineteen",
"profession": "mechanic"
}
]
}
например, вы можете перечислять объекты или объекты acces по числовому индексу.
помните, что json - это структура хранения, а не динамический сортировщик или индексатор.
используйте данные, хранящиеся в json, для создания индексов по мере необходимости и доступа к данным.
Ответ 7
У меня есть сомнения, как получить доступ к объектам в массиве народов выше?
Ответ 8
Вы можете использовать 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";
}
}