如何用C++读/写JSON?

bgtovc5b  于 2023-08-08  发布在  其他
关注(0)|答案(3)|浏览(113)

我想知道如何使用C++读/写JSON文件。我将使用这个文件来存储玩家信息和设置一个简单的游戏,我做的。这不是什么花哨的东西,只是一个游戏机数字猜谜游戏,但我只是用它来学习东西。
我必须知道如何阅读和编写JSON的特定部分。

z8dt9xmd

z8dt9xmd1#

使用一个库,它可以很容易地完成:

#include <nlohmann/json.hpp>
#include <iostream>

int main() {
    // read file
    auto json = nlohmann::json::parse("{\"value1\": \"string\"}");

    // mutate the json
    json["value1"] = "new string";

    // write to a stream, or the same file
    std::cout << json; // print the json
}

字符串
C没有处理json的内置程序。您可以实现自己的JSON数据结构,或者使用可用的数据结构,如nlohmann/jsonsimdjson
你可以使用纯C
和标准库创建自己的解析器,但我建议不要这样做,除非是为了学习。

agxfikkp

agxfikkp2#

使用struct_mapping可以做到:

#include "struct_mapping/struct_mapping.h"

#include <fstream>
#include <iostream>
#include <sstream>
#include <string>

struct Planet
{
    std::string name;
    double mass;
    bool populated;
};

int main()
{
    struct_mapping::reg(&Planet::name, "name");
    struct_mapping::reg(&Planet::mass, "mass");
    struct_mapping::reg(&Planet::populated, "populated");

    Planet planet;

    auto stream = std::ifstream("planet.json");
    struct_mapping::map_json_to_struct(planet, stream);

    planet.name = "Mars";
    planet.populated = false;

    std::ostringstream out_json_data;
    struct_mapping::map_struct_to_json(planet, out_json_data, "  ");

    std::cout << out_json_data.str() << std::endl;
}

字符串
数据文件示例

{
  "name": "Earth",
  "mass": 1234,
  "populated": true
}

ylamdve6

ylamdve63#

我 Package 了boost属性树,它围绕类和宏初始化,它接近类型反射(但它仍然缺少一个反射库来完成它)。它还支持类型嵌套,这是很多所谓的“奇妙的json”库在你深入研究时所达不到的。
假设你有一个类,你想在JSON中序列化或反序列化:
我会写在我的cpp里

class MyClass: public virtual Algorithm::Interface::ISimpleSerializedType
{
    public:
    int a;
    string b;
    // could be simplified further via a variadic macro to generate //SimplePropertyTree
    virtual Algorithm::Interface::IPropertyTree SimplePropertyTree(Algorithm::Interface::IPropertyTree& pt, bool toPropertyTree)
    {
        PSER(a, int)
        PSER(b, string)
    }
};

字符串
JSON看起来像{ a:“% 1”B:“somestring”}
我的读和写单元测试/片段看起来像这样:

//write 
MyClass entity;
    entity.a = 1;
    entity.filename = "test.json";
    entity.ToFile();
    // read
    MyClass entity;
    entity.filename = "test.json";
    entity.FromFile(); // everything is loaded

Algorithm::Interface::ISimpleSerializedType代码

#ifndef I_SIMPLE_SERIALIZED_TYPE_H
#define I_SIMPLE_SERIALIZED_TYPE_H
#include "IType.h"
#include "IFileSerializer.h"
namespace Algorithm
{
    namespace Interface
    {
        // Class contract that exposes common methods for which to extend
        class ISimpleSerializedType : public virtual IType,public virtual IFileSerializer
        {
            public:
            virtual IPropertyTree  ToPropertyTree(void){
                IPropertyTree pt;
                return SimplePropertyTree(pt,true);
            };

            // method which extracts the values from property tree
            virtual void FromPropertyTree(IPropertyTree&  pt){
                auto tree = SimplePropertyTree(pt,false);
                pt = tree._pt;
            };
            
            protected:
            // need to implement this
            virtual IPropertyTree SimplePropertyTree(IPropertyTree&  pt,bool ToPropertyTree)
            {
                
                return pt;
            }
        };
    }
}
#endif


代码ITYPE

#ifndef ITYPE_H
#define ITYPE_H
#include <sstream>
#include <string>
#include <vector>
#include <string>
#include "IPropertyTree.h"
#include <fstream>
// macross to simplify streaming property tree
#define __str__(s) #s
#define PADD(s) {\
try\
{\
std::string ss = std::to_string(s);\
std::string key = std::string(__str__(s));\
pt.add(key,ss);\
}\
catch (std::exception ex)\
{\
}\
}
#define PADDS(s) {\
try\
{\
std::string key = std::string(__str__(s));\
pt.add(key,s);\
}\
catch (std::exception ex)\
{\
}\
}
#define PADDBASE(BASE){\
auto st = std::string(__str__(BASE));\
auto pt2 = BASE##ToPropertyTree();\
pt.addPropertyTree(st, pt2);\
}
#define PADDMEMBER(membervar) {\
auto st = std::string(__str__(membervar));\
LOGIT1(st)\
auto _pt = membervar.ToPropertyTree();\
pt.addPropertyTree(st, _pt);\
}

// PGET 
#define PGET(VAR,type) {  std::string s(__str__(VAR));\
VAR = pt.get<type>(s); }

#define PGETBASE(VAR) {\
try\
{\
auto st = std::string(__str__(VAR));\
auto ptBase##VAR = pt.getChild(st); \
VAR##FromPropertyTree(ptBase##VAR);\
}\
catch (...)\
{\
}\
}
#define PGETMEMBER(membervar) {\
auto st = std::string(__str__(membervar));\
auto pt2 = pt.getChild(st);\
membervar.FromPropertyTree(pt2);\
}
///////////////
/// PGET2

#define PGET2(VAR,type) {  std::string s(__str__(VAR));\
VAR = pt._pt.get<type>(s); }

#define PGET2BASE(VAR) {\
try\
{\
auto st = std::string(__str__(VAR));\
auto ptBase##VAR = pt._pt.getChild(st); \
VAR##FromPropertyTree(ptBase##VAR);\
}\
catch (...)\
{\
}\
}
#define PGET2MEMBER(membervar) {\
auto st = std::string(__str__(membervar));\
auto pt2 = pt_pt.getChild(st);\
membervar.FromPropertyTree(pt2);\
}



// PSerialize uses a implied type bool ToPropertyTree and pt
#define PSER(VAR,type) if(toPropertyTree) {\
std::cout << "padd" << std::endl;\
PADD(VAR)\
} else {\
std::cout << "pget" << std::endl;\
PGET(VAR,type)\
}
#define PSERS(VAR) if(toPropertyTree) {\
PADDS(VAR)\
} else {\
PGET(VAR,std::string)\
}
#define PSERBASE(VAR)if(toPropertyTree) {\
PADDBASE(VAR)\
} else {\
PGET2BASE(VAR)\
}

#define PSERMEMBER(membervar)if(toPropertyTree) {\
PADDMEMBER(membervar) \
} else {\
PGET2MEMBER(membervar) \
}

namespace Algorithm
{
    namespace Interface
    {
        // Class contract that exposes common methods for which to extend
        class IType
        {
            public:
                IType() {};
            // causes problems with hiberlite when you derive it
            // from MVC so omitting this
            //  IType(IType& rhs) { *this = rhs; }
            virtual ~IType(){}; // destructor
            // methods don't communicate tho the key just the value

            // like stl containers returns size of type
            virtual size_t size(void){ return sizeof(IType);};

            // says the maximum size of the type
            virtual size_t max_size(void) { return sizeof(IType); };

            virtual void ToString(char* data,size_t& dataSize){ /* not implemented*/ };
            virtual void FromString(char* data,size_t& dataSize){};

            IType& operator=(const IType& rhs){
                std::string s;
                IType& rhsRef = const_cast<IType&>(rhs);
                size_t size = rhsRef.size();
                s.resize(size);
                rhsRef.ToString(const_cast<char*>(s.c_str()), size);
                FromString(const_cast<char*>(s.c_str()),size);
                return *this;
            };

            // must be friended methods
            // istream extraction operators terminated by std::endl for each respective subtype
            // ostream extraction operators terminated by std::endl for each respective subtype

            // encode the stream to stream with variable name + value name. Useful for key value streams;
            virtual IPropertyTree  ToPropertyTree(void){
                IPropertyTree pt;
                return pt;
            };

            // method which extracts the values from property tree
            virtual void FromPropertyTree(boost::property_tree::ptree&  typesEncodedInAPropertyTree){
                IPropertyTree pt;
                pt._pt = typesEncodedInAPropertyTree;
                FromPropertyTree(pt);
            };

            // method which extracts the values from property tree
            virtual void FromPropertyTree(IPropertyTree& typesEncodedInAPropertyTree) {

            };

            // call a serializer here
            // method instructs how to write to file by calling the approppriate serializer
            virtual void ToFile(void){

            };

            virtual void FromFile(void) {};
            virtual std::string TypeName(void) { return ""; };

        protected:
            inline bool exist(const std::string& name)
            {
                std::ifstream file(name);
                if (!file)            // If the file was not found, then file is 0, i.e. !file=1 or true.
                    return false;    // The file was not found.
                else                 // If the file was found, then file is non-0.
                    return true;     // The file was found.
            }
        };
    }
}
#endif

Code For IPropertyTree

#ifndef I_PROPERTY_TREE_H
#define I_PROPERTY_TREE_H
#include <boost/property_tree/ptree.hpp>
#include <memory>
#include <map>
#include <string>
#include <vector>
#include <iostream>
namespace Algorithm
{
    namespace Interface
    {
        class IPropertyTree
        {
            const std::string attributePrefix = ".<xmlattr>."; // attribute prefix to reference a attribute within boost property tree
            // https://stackoverflow.com/questions/3690436/how-are-attributes-parsed-in-boost-propertytree
            std::string BuildAttributeInsertionKey(std::string& key, std::string& attributeKey) { return key + attributePrefix + attributeKey; };

            public:
                boost::property_tree::ptree _pt; // good reference reading https://theboostcpplibraries.com/boost.propertytree
                    const IPropertyTree& operator=(const IPropertyTree& pt){
                    this->_pt = pt._pt;
                    return *this;};
                IPropertyTree(void) :_pt() {};
                IPropertyTree(boost::property_tree::ptree& pt) : _pt(pt) {};
                // usually only accessed by the serializers don't manually edit this
                boost::property_tree::ptree& GetBoostPropertyTree(void) { return _pt; };
                #ifdef _WIN32
                // key/value get and set
                template <class T>
                    void add(std::string& key, T& value)
                    {
                    _pt.put(key, value);
                };
                #else
                template <class T>
                    void add(std::string key, T value)
                    {
                    _pt.put(key, value);
                };
                #endif
                template <class T>
                T get(std::string& path) {
                    return  _pt.get<T>(path);
                };
                // attribute get/set
                template <class T>
                void addAttribute(std::string& keyName, std::string& attributeKey, T& attributeValue) {
                    _pt.add(BuildAttributeInsertionKey(keyName, attributeKey), std::to_string(attributeValue));
                }

                IPropertyTree getChild(std::string& key)
                {
                    return IPropertyTree(_pt.get_child(key));
                }

                template <class T>
                T getAttribute(std::string& keyPath, std::string& attributeName) {
                    return  _pt.get<T>(BuildAttributeInsertionKey(keyPath, attributeName));
                }

            void addPropertyTree(std::string& keyOfChildTree,IPropertyTree& tree)
                {
                _pt.add_child(keyOfChildTree,tree.GetBoostPropertyTree());
            };

            void addAttribute(std::string& keyName,std::string& attributeKey, std::string& attributeValue)
            {
                    _pt.add(BuildAttributeInsertionKey(keyName,attributeKey), attributeValue);
            };
        };
    }
}
#endif

Code For IFileSerializer
#ifndef I_FILE_SERIALIZER_H
#define I_FILE_SERIALIZER_H
#include "IJSONSerialize.h"
#include "IType.h"
#include "../../Tools/Diagnostics/Logger/Logger.h" // this uses LOGIT but you can just replace with std::cout
#include <cstdint>
#include <cstdlib>
#include <string>

namespace Algorithm
{
    namespace Interface
    {
        class IFileSerializer;
        // a Serializer for JSON
        class IFileSerializer : public virtual Algorithm::Interface::IType
        {
           public:

           std::string filename;
           IFileSerializer(void):Algorithm::Interface::IType(),filename(){};

          virtual void ToFile(void)
         {
                std::string msg = TypeName() + "::ToFile()";
                LOGIT1(msg)
                    std::string testJSON(filename);
                    auto pt = ToPropertyTree();
                    msg = TypeName() + "::ToFile() calling IJSON serialize";
                LOGIT1(msg)
                    Algorithm::Interface::IJSONSerialize test(testJSON, pt);
                msg = TypeName() + "::ToFile() WriteFile";
                LOGIT1(msg)
                    test.WriteFile();
        };

        virtual void FromFile(void)
        {
            auto msg = TypeName() + "::FromFile()\n";
            LOGIT1(msg)
            std::string testJSON(filename);
            auto pt = ToPropertyTree();
            Algorithm::Interface::IJSONSerialize test(testJSON, pt);
            test.ReadFile();
            this->FromPropertyTree(test.GetPropertyTree());
        };

        virtual Algorithm::Interface::IPropertyTree  ToPropertyTree(void) { Algorithm::Interface::IPropertyTree pt; return pt;};

        // method which extracts the values from property tree
        virtual void FromPropertyTree(Algorithm::Interface::IPropertyTree& pt) {};

        void ParseServerArgs(char** argv, int argc){
            std::string msg2="IFileSerializer::ParseServerArgs";
            LOGIT1(msg2)
            filename = "config.json";
            if(exist(filename))
            {
                std::string msg = "IFileSerializer::Calling FromFile";
                LOGIT1(msg)
                FromFile();
            }
            else
            {
                std::string msg = "IFileSerializer::Calling ToFile";
                LOGIT1(msg)
                ToFile(); // write it back so next time you can feed in the json
            }
        };
        }; // end class
    }
}
#endif

IJSONSerialize Code

#ifndef IJSONSERIALIZE_H
#define IJSONSERIALIZE_H
#include <string>
#include <vector>
#include <iostream>
#include <boost/property_tree/json_parser.hpp>
#include "IPropertyTree.h"
namespace Algorithm
{
    namespace Interface
    {
    // object that provides facilities to serialize JavaScript Object Notation(JSON)
    // citation: https://stackoverflow.com/questions/4586768/how-to-iterate-a-boost-property-tree
    class IJSONSerialize
    {
        IPropertyTree _pt;
        std::string _filename;
        public:
        IJSONSerialize(const std::string& filename, IPropertyTree& pt):_pt(pt),_filename(filename){

        };
    
    virtual void WriteFile(void){
        try
        {
            boost::property_tree::json_parser::write_json(_filename, _pt.GetBoostPropertyTree());
        }
        catch(std::exception ex)
        {
            std::cerr << "can't write json file " << _filename;
        }
    };

    virtual void WriteAsAString(std::string& outString)
    {
        std::stringstream ss;
        boost::property_tree::write_json(ss, _pt.GetBoostPropertyTree());
        outString = ss.str();
    };
    
    virtual void ReadFile(void){
         try 
         {
             boost::property_tree::read_json(_filename, _pt.GetBoostPropertyTree());
         }
         catch(const boost::property_tree::json_parser_error &jpe)
         {
                //do error handling
                std::cerr << "can't read json file " << _filename <<jpe.what();
         }
    };
    
    virtual void ReadFromString(std::string& s){
        try
        {
         std::stringstream ss;
         ss << s;
        auto pt = _pt.GetBoostPropertyTree(); boost::property_tree::json_parser::read_json(ss, pt);
        }
        catch(std::exception)
        {
            
        }
    };
    virtual std::string WriteToString(void){
        std::stringstream ss;
        boost::property_tree::json_parser::write_json(ss,_pt.GetBoostPropertyTree());
        return ss.str();
    };
    
    // use to retrieve all the values but
    virtual IPropertyTree& GetPropertyTree(void){
        return _pt;
    };
    
};
    }
}
#endif


如果缺少任何代码,您可以在我的bitbucket跨平台C++网络模板中找到它,该模板构建在boost asio之上。代码在这里:https://bitbucket.org/ptroen/crossplatformnetwork/src/master/
同样,如果你错过了注解,不想使用LOGIT,你可以找到并替换为std::cout
注意上面的代码是可以工作的,但是如果你研究的足够多的话,它们是一些技术债务,可以被优化,甚至更像反射
无论如何,希望你觉得这有用

相关问题