问题 用C ++读取json文件


我正在尝试读取JSON文件。到目前为止,我一直专注于使用 jsoncpp 图书馆。但是,我很难理解文档。任何人都可以用非专业术语解释它的作用吗?

说我有一个 people.json 看起来像这样:

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

当我读到这个时会发生什么?我可以创建某种数据结构吗? people 我可以索引 Anna 和 Ben 以及 age 和 profession?什么是数据类型 people?我认为它会类似于(嵌套)地图,但地图值总是必须具有相同的类型,不是吗?

我之前使用过python,而我的“目标”(可能是C ++的错误设置)是获得等效的嵌套python字典。


6369
2017-08-25 13:55


起源

fwiw:我已经成功使用了这个C ++ json解析库 github.com/cierelabs/json_spirit - Chris Beck
请注意,JSON(与JavaScript相反)要求密钥用双引号括起来。 - el.pescado


答案:


  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对象。


8
2017-08-25 14:37



谢谢!我现在明白了这个想法。但是,它还没有完成工作:如果我只是添加 json-forwards.h, json.h 和 jsoncpp.cpp 到项目我得到一个错误消息“无效的操作数到二进制表达式('std :: ifstream和'Json :: Value'”在行people_file >> people。如果我确实添加了所有文件 include/ 我收到一条错误消息“来自读者的错误:*第1行,第1列语法错误:值,对象或数组预期。”标题搜索路径设置为'include /'和'dist /'。 - user3515814
我猜你必须包括在内 json/json.h 代替 json.h。我不完全确定,因为我使用了jsoncpp已经有一段时间了。我发现了一个更简单的选择 nlohmann json。它具有几乎相同的功能,非常易于使用。您只需要包含一个文件, #include<json.hpp>。你可能想看看它。 - Pooja Nilangekar
人们被宣布为 json::Value people;?声明遗失了 - Francesco Boi


看着 这个。我找到了使用json格式最方便的方法。 它的设计就像一个STL容器,它的使用非常直观。


4
2017-10-11 11:03





本质上,javascript和C ++在两个不同的原则上工作。 Javascript创建一个“关联数组”或哈希表,它将字符串键(字段名称)与值匹配。 C ++在内存中布局结构,所以前4个字节是一个整数,这是一个年龄,然后我们可能有一个固定的32字节字符串代表“职业”。

因此,javascript将处理“年龄”在一个记录中为18而在另一个记录中为“十九”的事情。 C ++不能。 (但是C ++要快得多)。

因此,如果我们想在C ++中处理JSON,我们必须从头开始构建关联数组。然后我们必须用它们的类型标记值。它是一个整数,一个实数值(可能返回为“double”),boolean,一个字符串?因此,JSON C ++类是相当大的代码块。实际上我们正在做的是在C ++中实现一些javascript引擎。然后,我们将JSON解析器作为字符串传递给JSON,并对其进行标记,并为我们提供从C ++查询JSON的函数。


1
2017-10-11 11:14





用于读取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
2018-02-04 02:47



谢谢你的回答,你能否分享为什么你提供这个作为为用户提供一些上下文的答案。 - Daniel
@Daniel我添加了上下文(“读取json配置文件”)。 - Sandesh Kumar Sodhi


存储这样的人

{"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中的数据来根据需要构建索引并访问数据。


0
2017-10-31 14:14