本文主要會介紹怎么使用Google Protocol的Lib來序列化我們的數(shù)據(jù),方法很多種,本文只介紹其中的三種,其他的方法讀者可以通過自行研究摸索。但總的來說,序列化數(shù)據(jù)總的來說分為以下倆步:1)使用數(shù)據(jù)源填充數(shù)據(jù)結(jié)構(gòu),無論數(shù)據(jù)源來自文件還是內(nèi)存還是標(biāo)準(zhǔn)輸入 2)利用Lib提供的序列化接口將數(shù)據(jù)結(jié)構(gòu)序列化,然后存儲在內(nèi)存或者磁盤上
一、填充數(shù)據(jù)結(jié)構(gòu) 從數(shù)據(jù)源中獲取數(shù)據(jù),這兒的數(shù)據(jù)源可能來自磁盤上的一個文件或者內(nèi)存中存儲的一段數(shù)據(jù)或者來自標(biāo)準(zhǔn)輸入的數(shù)據(jù)。我們需要做的就是,將AddressBook這個數(shù)據(jù)結(jié)構(gòu)中的各個字段填充。本例中是通過AddressBook提供的add_person函數(shù)來獲得一個Person的指針,從而對其進行填充,如下代碼所示: //地址簿數(shù)據(jù)定義 AddressBook addressBook; //第一個聯(lián)系人的數(shù)據(jù)定義與初始化 Person *personMe = addressBook.add_person(); personMe->set_id(1); personMe->set_name("royen"); personMe->set_email("zwg19891129@163.com"); personMe->set_unsure("19bf173a0e87ab"); //第二個聯(lián)系人的數(shù)據(jù)定義與初始化 Person *personHim = addressBook.add_person(); personHim->set_id(2); personHim->set_name("XXX"); personHim->set_email("XXX@XXX.com"); personHim->set_unsure("19bf173a0e87ab"); //personMe的手機號碼數(shù)據(jù)定義與初始化 Person_PhoneNumber *phoneNumberMobile = personMe->add_phone(); phoneNumberMobile->set_number("15996110120"); phoneNumberMobile->set_type(Person_PhoneType_MOBILE); //personMe的座機號碼數(shù)據(jù)定義與初始化 Person_PhoneNumber *phoneNumberHome = personMe->add_phone(); phoneNumberHome->set_number("0256110120"); phoneNumberHome->set_type(Person_PhoneType_HOME); //personHim的一個號碼數(shù)據(jù)定義與初始化 Person_PhoneNumber *phoneNumberHim = personHim->add_phone(); phoneNumberHim->set_number("15996111111"); phoneNumberHim->set_type(Person_PhoneType_HOME); 很容易看出,上述代碼即在地址簿中添加了倆個聯(lián)系人,然后又分別填充各個聯(lián)系人的數(shù)據(jù)信息,通過上述代碼一個地址簿的數(shù)據(jù)便準(zhǔn)備好了。
二、序列化數(shù)據(jù) 其實通過看編譯器生成的AddressBook這個類所提供的方法名,既可以大致知道有哪些序列化的方式,如下所示: 從上圖可以看出,可利用序列化的方法很多,本文中主要使用SerializeToString、SerializeToCodedStream以及SerializeToOstream來完成序列化。 下面就分別就這幾種方式來介紹下: 1) SerializeToCodedStream方式 首先可以知道該函數(shù)的原型是bool SerializeToCodedStream(std::ostream *),所以使用該函數(shù)需要結(jié)合C++的fstream流,代碼如下: //方法一: 使用SerializePartialToOstream來序列化,注意ios::binary以二進制流寫入文件 fstream fserial("addressbook.data",ios::out | ios::trunc | ios::binary); if (!addressBook.SerializePartialToOstream(&fserial)) { cerr<<"Failed to serial address book data!\n"; return; } cout<<"Serial address book data successfully!\n"; fserial.close(); fserial.clear(); 可以看出,采用這種方法相當(dāng)?shù)谋憬?,而且也很簡潔,但有個缺點就是輸出到文件的編碼格式不好控制,所以可以使用下面介紹的這種方法。
2)SerializeToString方式 函數(shù)原型為bool SerializeToString(std::string* output) ,所以可以講填充在數(shù)據(jù)結(jié)構(gòu)AddressBook中的數(shù)據(jù)取出存到一個string對象中,然后再以二進制流的方式將其寫入到磁盤文件中,代碼如下: FILE *g_AddressBook = fopen("addressbook.data","wb,ccs = UNICODE"); if( NULL == g_AddressBook ) { cerr<<"Create addressbook.data failed!\n"; return ; } string serialStream = ""; if( !addressBook.SerializePartialToString(&serialStream) ) { cerr<<"Failed to serial addressbook data!\n"; return; } fwrite( serialStream.c_str(),sizeof(char),addressBook.ByteSize(),g_AddressBook); cout<<"serial address successfully!\n"; if( g_AddressBook ) { fclose(g_AddressBook); g_AddressBook = NULL; } 上述代碼稍微繁瑣了點,但是也是一種序列化的方式,通過結(jié)合使用C庫中的文件操作函數(shù),可以更方便的定制輸出文件。
3)SerializeToCodedStream方式 該方式主要指用到的google buffer的庫中提供的一組數(shù)據(jù)流操作對象,在使用這些對象之前需要引入一些頭文件,如下所示: #include <google/protobuf/io/zero_copy_stream_impl.h> #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/io/coded_stream.h> using namespace::google::protobuf::io; 該方式也結(jié)合C庫的open與write函數(shù),序列化部分的代碼如下: int fd = _open("addressbook.data", _O_WRONLY |_O_CREAT| _O_BINARY, _S_IREAD|_S_IWRITE); if( -1 == fd ) { cerr<<"Create addressbook.data failed!\n"; return ; } char tmpArr[MAX_SIZE]; memset(tmpArr,0,sizeof(tmpArr)); ZeroCopyOutputStream *raw_output = new ArrayOutputStream(tmpArr,addressBook.ByteSize()+1); CodedOutputStream* coded_output = new CodedOutputStream(raw_output); if( !addressBook.SerializeToCodedStream( coded_output )) { cerr<<"Fail to serial addressbook data!\n"; return; } _write(fd,tmpArr,addressBook.ByteSize()+1); cout<<"serial address successfully!\n"; delete coded_output; delete raw_output; close(fd); 本文暫時介紹這三種序列化話方式,還有像SerializeToArray以及SerializeToFileDescriptor等方式都應(yīng)該比較類似,所以感興趣的朋友可以自己動手試試。 下篇文章再稍微介紹下反序列化的方法,但是應(yīng)該不會太多內(nèi)容,畢竟都方法都很相似。 |
|