序列化:内存中保存的对象-》字节
反序列化:字节-》内存中保存的对象
①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