Чтение файлов json на C++

Я пытаюсь прочитать в файле JSON. До сих пор я сосредоточился на использовании jsoncpp библиотека. Тем не менее, документация довольно трудно понять для меня. Может ли кто-нибудь объяснить в светских терминах, что он делает?

скажем, у меня есть people.json выглядит так:

{"Anna" : { 
      "age": 18,
      "profession": "student"},
 "Ben" : {
      "age" : "nineteen",
      "profession": "mechanic"}
 }

что происходит, когда я читаю это? Могу ли я создать какую-то структуру данных people который я могу индексировать по Anna и Ben а также age и profession? Каким будет тип данных people? Я думал, что это будет что-то похожее на (вложенную) карту, но Значения карты всегда должны иметь один и тот же тип, не так ли?

я работал с python раньше, и моя "цель" (которая может быть плохо установлена для C++)-получить эквивалент вложенного словаря python.

5 ответов


  1. Да, вы можете создать вложенную структуру данных people, который может быть проиндексирован Anna и Ben. Однако, вы не можете индексировать его напрямую по age и profession (Я вернусь к этой части кода).

  2. тип данных 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 только на основе иерархии входных данных.


посмотреть репозиторий JSON nlohmann на GitHub. Я обнаружил, что это самый удобный способ работы с JSON.

Он разработан, чтобы вести себя так же, как контейнер STL, что делает его использование очень интуитивным.


по существу javascript и C++ работают на двух разных принципах. Javascript создает "ассоциативный массив" или хэш-таблицу, которая соответствует строковому ключу, который является именем Поля, значению. C++ выкладывает структуры в память, поэтому первые 4 байта-это целое число, которое является возрастом, тогда, возможно, у нас есть фиксированная 32-байтовая строка, которая представляет "профессию".

таким образом, javascript будет обрабатывать такие вещи, как" возраст "18 в одной записи и" девятнадцать " в другой. C++ не может. (Однако C++ намного быстрее).

Итак, если мы хотим обрабатывать JSON в C++, мы должны построить ассоциативный массив с нуля. Затем мы должны пометить значения их типами. Это целое число, реальное значение (возможно, возвращаемое как "double"), логическое, строка? Из этого следует, что класс JSON C++ является довольно большим куском кода. Эффективно то, что мы делаем, - это реализация немного движка javascript на C++. Мы затем передаем наш формат JSON парсер JSON в виде строки, и он tokenises его, и дает нам функции для запроса JSON из C++.


пример (с полным исходным кодом) для чтения файла конфигурации 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
 > 

хранение людей, как это

{"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, для построения индексов по мере необходимости и доступа к данным.