web-dev-qa-db-fra.com

Lecture de fichiers json en C++

J'essaie de lire dans un fichier JSON. Jusqu'à présent, je me suis concentré sur l'utilisation de la bibliothèque jsoncpp. Cependant, la documentation est assez difficile à comprendre pour moi. Quelqu'un pourrait-il expliquer en termes simples ce qu'il fait? 

Dites que j'ai un people.json qui ressemble à ceci:

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

Qu'est-ce qui se passe quand je lis ceci dans? Puis-je créer une sorte de structure de données people que je peux indexer par Anna et Ben ainsi que age et profession? Quel serait le type de données de people? J'ai pensé que cela ressemblerait à une carte (imbriquée), mais les valeurs de carte doivent toujours avoir le même type, n'est-ce pas?

J'ai déjà travaillé avec python auparavant et mon objectif (qui peut être mal défini pour C++) est d'obtenir l'équivalent d'un dictionnaire python imbriqué. 

11
user3515814
  1. Oui, vous pouvez créer une structure de données imbriquée people qui peut être indexée par Anna et Ben. Cependant, vous ne pouvez pas l'indexer directement par age et profession (j'aborderai cette partie dans le code).

  2. Le type de données de people est de type Json::Value (défini dans jsoncpp). Vous avez raison, cela ressemble à la carte imbriquée, mais Value est une structure de données définie de manière à ce que plusieurs types puissent être stockés et accessibles. Cela ressemble à une carte avec string comme clé et Json::Value comme valeur. Il peut également s'agir d'un mappage entre unsigned int en tant que clé et Json::Value en tant que valeur (dans le cas de tableaux JSON). 

Voici le code:

#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.

Comme vous pouvez le constater, vous ne pouvez indexer l'objet json qu'en fonction de la hiérarchie des données d'entrée.

9
Pooja Nilangekar

Consultez le référentiel JSON de nlohmann sur GitHub . J'ai trouvé que c'était le moyen le plus pratique de travailler avec JSON.

Il est conçu pour se comporter comme un conteneur STL, ce qui rend son utilisation très intuitive.

5
Arsen

Exemple (avec le code source complet) pour lire un fichier de configuration 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
 > 
1
Sandesh Kumar Sodhi

Essentiellement, javascript et C++ fonctionnent sur deux principes différents. Javascript crée un "tableau associatif" ou une table de hachage, qui correspond à une clé de chaîne, qui est le nom du champ, à une valeur. C++ dispose des structures en mémoire, donc les 4 premiers octets sont un entier, qui est un âge, alors peut-être avons-nous une chaîne fixe de 32 octets qui représente le "métier".

Donc, javascript gérera des choses comme "l'âge" étant 18 ans sur un disque et "19 ans" sur un autre. C++ ne peut pas. (Cependant, C++ est beaucoup plus rapide).

Donc, si nous voulons gérer JSON en C++, nous devons construire le tableau associatif à partir de la base. Ensuite, nous devons étiqueter les valeurs avec leurs types. S'agit-il d'un entier, d'une valeur réelle (probablement renvoyée sous la forme "double"), d'une valeur booléenne? Il s'ensuit qu'une classe JSON C++ est un assez gros morceau de code. En pratique, nous implémentons un peu du moteur javascript en C++. Nous transmettons ensuite à notre analyseur JSON le JSON sous forme de chaîne, qui le marque et nous donne des fonctions pour interroger le JSON à partir de C++.

1
Malcolm McLean

stocker des peuples comme ça 

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

causera des problèmes, en particulier si différents peuples ont le même nom ..

plutôt utiliser un tableau stockant des objets comme celui-ci

{
  "peoples":[
       { 
           "name":"Anna",  
           "age": 18,
           "profession": "student"
       },
       {
           "name":"Ben",
           "age" : "nineteen",
           "profession": "mechanic"
       } 
  ]
}

comme ceci, vous pouvez énumérer des objets, ou accéder à des objets par index numérique . rappelez-vous que json est une structure de stockage, et non pas un trieur ou un indexeur dynamique .

0
christian audebert