分享
 
 
 

新手指南-序列化篇之二

王朝vc·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

序列化初步(翻译)

原著:http://www.codeproject.com/cpp/serialization_primer2.asp

在第一部分,我们学到了如何通过CArchive类的serialize()函数来序列化一个简单对象。象下面的程序这样:

int CFoo::serialize

(CArchive* pArchive)

{

int nStatus = SUCCESS;

// Serialize the object ...

ASSERT (pArchive != NULL);

TRY

{

if (pArchive->IsStoring()) {

// Write employee name and id

(*pArchive) << m_strName;

(*pArchive) << m_nId;

}

else {

// Read employee name and id

(*pArchive) >> m_strName;

(*pArchive) >> m_nId;

}

}

CATCH_ALL (pException)

{

nStatus = ERROR;

}

END_CATCH_ALL

return (nStatus);

}

这段代码有一个问题,如果我们错误的从数据文件中去读取并不存在的信息会怎么样?如果数据文件中在CString之后不是一个整数,那么serialize()函数将返回ERROR。这也不错,但是如果我们可以给错误定位,并返回一个更加详细的错误信息,比如INVALID_DATAFILE,那就更好了。我们可以通过对象签名来确认我们是在读取一个有效的数据文件。

对象签名

对象签名就是用一个字符串来识别一个对象。我们修改Cfoo类的定义来增加一个签名:

class CFoo

{

...

// Methods

public:

...

CString getSignature();

// Data members

...

protected:

static const CString Signature; // object signature

};

签名在Foo.cpp中申明:

// Static constants

const CString CFoo::Signature = "FooObject";

下一步,我们修改serialize()函数,在序列化对象的数据成员前先序列化这个签名。如果遇到无效的签名,或者签名丢失,那么可以认为我们在试图读取一个并不包含有Cfoo对象的数据存储。以下是读取有签名的对象的流程:

以下是流程实现代码:

int CFoo::serialize

(CArchive* pArchive)

{

int nStatus = SUCCESS;

bool bSignatureRead = false;

// Serialize the object ...

ASSERT (pArchive != NULL);

TRY

{

if (pArchive->IsStoring()) {

// Write signature

(*pArchive) << getSignature();

// Write employee name and id

(*pArchive) << m_strName;

(*pArchive) << m_nId;

}

else {

// Read signature - complain if invalid

CString strSignature;

(*pArchive) >> strSignature;

bSignatureRead = true;

if (strSignature.Compare (getSignature()) != 0) {

return (INVALID_DATAFILE);

}

// Read employee name and id

(*pArchive) >> m_strName;

(*pArchive) >> m_nId;

}

}

CATCH_ALL (pException)

{

nStatus = bSignatureRead ? ERROR : INVALID_DATAFILE;

}

END_CATCH_ALL

return (nStatus);

}

你必须确保你所有的对象都有唯一的签名。具体的签名内容并不重要。如果你正在开发一批产品,那么在公司范围内增加一个对象签名注册步骤是非常有帮助的。另一方面,开发者将不会给不同的对象使用相同的签名。如果你想让你的数据文件更难以被反解,那么你应该使用一个与对象名称没有明显任何关系的签名。

版本

如果你在产品的生命周期内进行升级,那么你也许要通过增加或者删除数据成员来修改Cfoo类结构。如果你只是为Cfoo发布新的版本,并且试图从数据存储中读取旧版本的对象,那么将会失败。这明显是不可以接受的。Cfoo的任何版本都应该可以让一个更旧版本恢复。

换句话说,Cfoo的序列化方法应该是向前兼容的。这个问题通过给对象增加版本是很容易完成的。与给对象增加签名相同,我们增加一个整数常量来指定这个对象的版本号。

class CFoo

{

...

// Methods

public:

...

CString getSignature();

int getVersion();

// Data members

...

protected:

static const CString Signature; // object signature

static const int Version; // object version

};

对象的版本号在Foo.cpp中申明

// Static constants

const CString CFoo::Signature = "FooObject";

const int CFoo::Version = 1;

下一步,我们修改serialize()函数,在序列化签名之后,序列化对象的数据成员之前序列化版本。如果遇到更新的版本,我们试图读取一个对象不支持的版本,那么,在下面的例子中,我们就返回一个状态标志UNSUPPORTED_VERSION。

int CFoo::serialize

(CArchive* pArchive)

{

int nStatus = SUCCESS;

bool bSignatureRead = false;

bool bVersionRead = false;

// Serialize the object ...

ASSERT (pArchive != NULL);

TRY

{

if (pArchive->IsStoring()) {

// Write signature and version

(*pArchive) << getSignature();

(*pArchive) << getVersion();

// Write employee name and id

(*pArchive) << m_strName;

(*pArchive) << m_nId;

}

else {

// Read signature - complain if invalid

CString strSignature;

(*pArchive) >> strSignature;

bSignatureRead = true;

if (strSignature.Compare (getSignature()) != 0) {

return (INVALID_DATAFILE);

}

// Read version - complain if unsupported

int nVersion;

(*pArchive) >> nVersion;

bVersionRead = true;

if (nVersion > getVersion()) {

return (UNSUPPORTED_VERSION);

}

// Read employee name and id

(*pArchive) >> m_strName;

(*pArchive) >> m_nId;

}

}

CATCH_ALL (pException)

{

nStatus = bSignatureRead && bVersionRead ? ERROR : INVALID_DATAFILE;

}

END_CATCH_ALL

return (nStatus);

}

Cfoo的版本1包含两个数据成员:一个CString类型(m_strName)和一个int类型(m_nId)。如果我们在版本2中增加第三个成员(例如: int m_nDept)。那么我们必须决定,当读取一个旧版本时,m_nDept应该初始化为多少。在下面的例子中,我们初始化m_nDept为1,意味着这个职员的部门为“未知”。

class CFoo

{

...

// Data members

public:

CString m_strName; // employee name

int m_nId; // employee id

int m_nDept; // department code (-1 = unknown)

};

我们需要将Foo.cpp中对象的版本号改为2。

const int CFoo::Version = 2;

最后,我们修改serialize()函数中读取对象的部分,如果我们读取的是一个旧版本的数据文件,将m_nDept初始化为-1。注意,文件保存总是用最新的版本。

int CFoo::serialize

(CArchive* pArchive)

{

...

// Serialize the object ...

ASSERT (pArchive != NULL);

TRY

{

if (pArchive->IsStoring()) {

...

// Write employee name, id and department code

(*pArchive) << m_strName;

(*pArchive) << m_nId;

(*pArchive) << m_nDept;

}

else {

...

// Read employee name and id

(*pArchive) >> m_strName;

(*pArchive) >> m_nId;

// Read department code (new in version 2)

if (nVersion >= 2) {

(*pArchive) >> m_nDept;

}

else {

m_nDept = -1; // unknown

}

}

}

CATCH_ALL (pException)

{

nStatus = bSignatureRead && bVersionRead ? ERROR : INVALID_DATAFILE;

}

END_CATCH_ALL

return (nStatus);

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有