序列化与反序列化

序列化:内存中保存的对象-》字节

反序列化:字节-》内存中保存的对象

①tinyxml2:序列化与反序列化xml

\

<Table name="PersonInfo">      //name="PersonInfo"是属性
  <Person Type="学生">  
        <Age age = "年龄">18</Age>  //Age是key,18是value
        <Height Hei = "身高">1.7</Height>
   </Person>
   <Age age = "年龄">30</Age>
   <Height Hei = "身高">1.8</Height>
</Table>
//类比类
class Table
{ //3个数据成员
    Person;
    Age;
    Height;
};
 

Test.xml 

 <?xml version="1.0"?>
<Table name="PersonInfo">
    <Person Type="学生"> 
        <Age age = "年龄">18</Age>
        <Height Hei = "身高">1.7</Height>
    </Person>
    <Person Type="教师">
        <Age age = "年龄">28</Age>
        <Height Hei = "身高">1.6</Height>
    </Person>
    <Person Type="警察">
        <Age age = "年龄">30</Age>
        <Height Hei = "身高">1.8</Height>
    </Person>
</Table>

#include <iostream>
#include <string>
#include <vector>

#include "tinyxml2.h"

using namespace std;

struct Programmer
{
    string name;
    int age;
    string phone;
    string address;
    vector<string> languages;
    vector<string> books;
};

void test0() 
{
    Programmer programmer {
        "Lina",
            71,
            "19888405103",
            "New York",
            {"C", "C++"},
            {
                "A tour of C++", 
                "C++语言的设计和演化",
                "The C++ Programming Language"
            }
    };
    cout << "sizeof(programmer): " << sizeof(programmer) << endl;

    using namespace tinyxml2;
    int count = 100000;
    clock_t start = clock();

    //执行10万次花费的时间
    while((count--) > 0) {
        //结构体-》xml对象
        XMLDocument doc;
        XMLElement * nameElem = doc.NewElement("name");
        nameElem->SetText(programmer.name.c_str());
        XMLElement * ageElem = doc.NewElement("age");
        ageElem->SetText(programmer.age);

        XMLElement * phoneElem = doc.NewElement("phone");
        phoneElem->SetText(programmer.phone.c_str());

        XMLElement * addressElem = doc.NewElement("address");
        addressElem->SetText(programmer.address.c_str());

        XMLElement * langElem1 = doc.NewElement("language");
        XMLElement * langElem2 = doc.NewElement("language");
        langElem1->SetText(programmer.languages[0].c_str());
        langElem2->SetText(programmer.languages[1].c_str());
        XMLElement * languagesElem = doc.NewElement("languages");
        languagesElem->InsertFirstChild(langElem1);
        languagesElem->InsertAfterChild(langElem1, langElem2);

        XMLElement * bookElem1 = doc.NewElement("book");
        XMLElement * bookElem2 = doc.NewElement("book");
        XMLElement * bookElem3 = doc.NewElement("book");
        bookElem1->SetText(programmer.books[0].c_str());
        bookElem2->SetText(programmer.books[1].c_str());
        bookElem3->SetText(programmer.books[2].c_str());
        XMLElement * booksElem = doc.NewElement("books");
        booksElem->InsertFirstChild(bookElem1);
        booksElem->InsertAfterChild(bookElem1, bookElem2);
        booksElem->InsertAfterChild(bookElem2, bookElem3);

        XMLElement * programmerElem = doc.NewElement("programmer");
        doc.InsertFirstChild(programmerElem);
        programmerElem->InsertFirstChild(nameElem);
        programmerElem->InsertAfterChild(nameElem, ageElem);
        programmerElem->InsertAfterChild(ageElem, phoneElem);
        programmerElem->InsertAfterChild(phoneElem, addressElem);
        programmerElem->InsertAfterChild(addressElem, languagesElem);
        programmerElem->InsertAfterChild(languagesElem, booksElem);

        if(count == 1) {
            //序列化:xml对象-》字节流
            XMLPrinter streamer;
            doc.Print(&streamer);
            cout << "size:" << streamer.CStrSize() << endl;
            cout << streamer.CStr() << endl;

            cout << endl;

            //xml对象->结构体
            XMLElement *pRoot1 = doc.RootElement();//获取根节点
            XMLElement *pNode1 = pRoot1->FirstChildElement();//获得第一个子节点
            while(pNode1)
            {
                XMLElement *pChildNode1 = pNode1->FirstChildElement();
                const char* pValue; 
                if(pChildNode1 == nullptr)
                {
                    pValue = pNode1->GetText();
                    cout << pValue;
                }
                while(pChildNode1)
                {
                    cout << pChildNode1->GetText() << "; ";
                    pChildNode1 = pChildNode1-> NextSiblingElement();
                }
                cout << endl;
                pNode1 = pNode1->NextSiblingElement();
            }
        }
    }
    clock_t end = clock();
    cout << "time:" << (end - start) / 1000 << endl;


    //反序列化;解析xml文件
    XMLDocument Doc;
    Doc.LoadFile("Test.xml");
    XMLElement *pRoot=Doc.RootElement();//获取根节点
    XMLElement *pNode=pRoot->FirstChildElement("Person");//获得第一个Key为Person的子节点
    while (pNode) 
    { 
        XMLElement *pChildNode=pNode->FirstChildElement();//无参默认返回第一个子节点
        const char* pContent; 
        const XMLAttribute *pAttributeOfNode = pNode->FirstAttribute();//获取结点的第一个属性
        cout<< pAttributeOfNode->Value()<<":"; //打印属性value
        while(pChildNode) 
        { 
            pContent=pChildNode->GetText();//获得节点的Value
            cout<<pChildNode->FirstAttribute()->Value()<<":"<<pContent<<" ";
            pChildNode=pChildNode->NextSiblingElement();//获取下一个子结点

        }
        cout << endl;
        pNode=pNode->NextSiblingElement(); //获取下一个子节点

    }
} 

int main(void)
{
    test0();
    return 0;
}

  

②jsoncpp或nlohmann/json:序列号与反序列化json

使用nlohmann/json

把nlohmann文件夹放到/usr/include/下

#include <iostream>
#include <string>
#include <vector>

#include <nlohmann/json.hpp>

using namespace std;

struct Programmer
{
	string name;
	int age;
	string phone;
	string address;
	vector<string> languages;
	vector<string> books;
};
 
void test0() 
{
	Programmer programmer {
		"Lina",
		71,
		"19888405103",
		"New York",
        {"C", "C++"},
		{
			"A tour of C++", 
			"C++语言的设计和演化",
			"The C++ Programming Language"
		}
	};
	cout << "sizeof(programmer):" << sizeof(programmer) << endl;

	int cnt = 100000;
	clock_t start = clock();
	while(cnt-- > 0) {
        //结构体-》json对象
		nlohmann::json j;
		j["name"] = programmer.name;
		j["age"] = programmer.age;
		j["phone"] = programmer.phone;
		j["address"] = programmer.address;
		j["languages"] = programmer.languages;
		j["books"] = programmer.books;

		if(cnt == 1) {
			string jstr = j.dump();//序列化
			cout << "json's size:\n" << jstr.size() << endl;
			cout << jstr << endl << endl;

            //提取json对象中的数据
            cout << j["name"].get<string>() << endl;
            cout << j["age"].get<int>() << endl;
            cout << j["address"].get<string>() << endl;
            cout << j["languages"].get<vector<string>>()[0] << endl;
            cout << j["books"].get<vector<string>>()[0] << endl;
		}
	}
	clock_t end = clock();
	cout << "time:" << (end - start) / 1000 << endl;
} 
 
int main(void)
{
	test0();
	return 0;
}

namespace ns {
    //首先定义一个结构体
    struct person {
        std::string name;
        std::string address;
        int age;
    };
}

//更方便的转化方式

namespace ns {
    void to_json(json& j, const person& p) {
        j = json{{"name", p.name}, {"address", p.address}, {"age", p.age}};
    }

    void from_json(const json& j, person& p) {
        j.at("name").get_to(p.name);
        j.at("address").get_to(p.address);
        j.at("age").get_to(p.age);
    }
} // namespace ns

ns::person p {"Ned Flanders", "744 Evergreen Terrace", 60};
json j = p;
std::cout << j << std::endl;
// {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"}

// conversion: json -> person
auto p2 = j.get<ns::person>();

使用jsoncpp

#include <json/json.h>

struct Message
{
    Message()
        :_content_len(0)
         ,_id(0)
    {
        memset(_buf, 0 , sizeof(_buf));
    }
    int _content_len;//消息内容长度
    int _id;//消息id
    char _buf[1000];//消息内容
};


void SocketIO::readMsg(Message *pMsg)
{    
    string json_string;
    char buf[1000] = {0};
    //先收json字符串的长度
    int len;
    recv(_fd, &len, sizeof(int), MSG_WAITALL);
    //再收json字符串
    recv(_fd, buf, len, MSG_WAITALL);
    json_string = buf;
    //解析json风格的字符串
    Json::Reader reader;
    Json::Value result;
    reader.parse(json_string, result);
    pMsg->_content_len = result["len"].asInt();
    pMsg->_id = result["id"].asInt();
    strcpy(pMsg->_buf, result["buf"].asString().c_str());
}

void SocketIO::writeMsg(const Message & msg)
{
    //转换成json格式后发送
    Json::FastWriter writeInto;
    Json::Value resultInto;
    resultInto["id"] = msg._id;
    resultInto["len"] = msg._content_len;
    resultInto["buf"] = msg._buf;
    string json_string = writeInto.write(resultInto);//获得json格式的字符串
    //先发送json字符串的长度
    int len = json_string.size();
    send(_fd, &len, sizeof(int), 0);
    //再发送json字符串
    send(_fd, json_string.c_str(), json_string.size(), 0);
}

 

③protobuf

https://developers.google.cn/protocol-buffers/docs/proto3

安装
sudo apt-get install autoconf automake libtool curl make g++ unzip
cd protobuf-3.17.0
./autogen.sh
./configure
make
make check
sudo make install
sudo ldconfig # refresh shared library cache.



卸载
     $ sudo rm /usr/local/bin/protoc                //删除可执行文件
     $ sudo rm -rf /usr/local/include/google    //删除头文件
     $ sudo rm -rf /usr/local/lib/libproto*         //删除库文件

以.proto文件中的数据格式进行传输

programmer.proto

syntax = "proto3";

message Programmer{
    string name = 1; //1~15用1个字节编码,16~2047用2个字节编码
    int32 age = 2;  //编号是唯一的
    string phone = 3;
    string address = 4;
    repeated string lang = 5;
    repeated string book = 6;
    map<string, Project> projs = 7;
}

message Project {
    string name = 1;
    float price = 2;
}

message Foo {
  reserved 2, 15, 9 to 11;  //保留编号,暂时不使用2,15,9~11
  reserved "foo", "bar";  //保留字段
}

 message SearchResponse {
  repeated Result results = 1;
}

message Result {
  string url = 1;
  string title = 2;
  repeated string snippets = 3;
}

//等价于

message SearchResponse {
  message Result {
    string url = 1;
    string title = 2;
    repeated string snippets = 3; //repeated表示可重复
  }
  repeated Result results = 1;
}

//扩展

message SomeOtherMessage {
  SearchResponse.Result result = 1;

 message SampleMessage {
  oneof test_oneof { //oneof就类比union,要么是string,要么是SubMessage
    string name = 4;
    SubMessage sub_message = 9;
  }
}

 package foo.bar;  //类比namespace foo.bar
message Open { ... }   //Open是 foo.bar里面的东西

message Foo {
  ...
  foo.bar.Open open = 1;   //类比foo.bar::Open open = 1;
  ...
}

①先写一个.proto文件:programmer.proto

syntax = "proto3"; //表示要采用proto3的语法规则定义message,不指定protoc编译器会默认采用proto2的语法规则处理

message Programmer{
	string name = 1; //1~15用1个字节编码,16~2047用2个字节编码
	int32 age = 2;
	string phone = 3;
	string address = 4;
	repeated string lang = 5;
	repeated string book = 6;
	map<string, Project> projs = 7;
}

message Project {
	string name = 1;
	float price = 2;
}

②通过.proto生成.pb.cc和.pb.h文件

 protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR (这些都是其它语言的命令:--java_out=DST_DIR --python_out=DST_DIR --go_out=DST_DIR --ruby_out=DST_DIR --objc_out=DST_DIR --csharp_out=DST_DIR) path/to/file.proto         

protoc --proto_path=./ --cpp_out=./ ./*.proto    //proto_path是.proto的路径,--cpp_out是.pb文件输出的路径

③在写代码的时候使用第二步生成的代码

#include "programmer.pb.h"
#include <google/protobuf/text_format.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

using namespace std;
/* using namespace google::protobuf; */

#if 1
struct Programmer0
{
	string name;
	int age;
	string phone;
	string address;
	vector<string> languages;
	vector<string> books;
};
#endif
 
void test0() 
{
	int count = 100000;
	Programmer0 programmer0 {
		"Bjarne Stroustrup",
		71,
		"19888405103",
		"Morgan Stanley in New York City",
		{"C", "C++"},
		{"A tour of C++", 
		 "C++语言的设计和演化",
		 "The C++ Programming Language"
		}
	};
	clock_t start = clock();
	while(count-- > 0) {

		using namespace google::protobuf;

        Programmer programmer;
		programmer.set_name(programmer0.name);
		programmer.set_age(programmer0.age);
		programmer.set_phone(programmer0.phone);
		programmer.set_address(programmer0.address);
		
		programmer.add_lang(programmer0.languages[0]);
		programmer.add_lang(programmer0.languages[1]);
		programmer.set_lang(0, "Java");

		programmer.add_book(programmer0.books[0]);
		programmer.add_book(programmer0.books[1]);
		programmer.add_book(programmer0.books[2]);

		if(count == 1) {
			string bytes;
			programmer.SerializeToString(&bytes);//序列化
			cout << bytes.size() << endl;
			cout << bytes << endl << endl;

			std::ofstream ofs0("./program.txt", std::ios::out | std::ios::binary);
			if(ofs0) {
				ofs0.write(bytes.c_str(), bytes.size());
			}
			ofs0.close();

			Programmer prog;
			prog.ParseFromString(bytes);//反序列化
			cout << "prog's message:" << endl
				 << prog.name() << endl
				 << prog.age() << endl
				 << prog.address() << endl
				 << prog.phone() << endl
				 << "book's size: " << prog.book_size() << endl
				 << prog.book(0) << endl
				 << prog.book(1) << endl
				 << prog.book(2) << endl
				 << "language's size:" << prog.lang_size() << endl
				 << prog.lang(0) << endl
				 << prog.lang(1) << endl;

			//将文本信息保存到字符串中
			/* string bytes2; */
			/* google::protobuf::TextFormat::PrintToString(programmer, &bytes2); */
			/* cout << bytes2.size() << endl */
			/* 	 << "bytes2:" << endl << bytes2 << endl; */
		}
	}//end of while
	clock_t end = clock();
	cout << "time:" << (end - start) / 1000 << endl;

	/* TextFormat::PrintToString(programmer, & bytes); */
	/* cout << bytes.size() << endl */
	/* 	 << bytes << endl << endl; */
	
#if 0
	//输出到文件中
	if(ofs) {
		auto output = new google::protobuf::io::OstreamOutputStream(&ofs);
		google::protobuf::TextFormat::Print(programmer, output);
		delete output;
	}
	ofs.close();
#endif


	/* char buff[1024] = {0}; */
	/* programmer.SerializeToArray(buff, 1024); */
	/* cout << strlen(buff) << endl; */
	/* cout << buff << endl; */
} 
 
int main(void)
{
	test0();
	return 0;
}

g++ programmer.cc programmer.pb.cc -lprotobuf

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值