串行化SerializationWord文档格式.docx

上传人:b****6 文档编号:16384511 上传时间:2022-11-23 格式:DOCX 页数:15 大小:24.40KB
下载 相关 举报
串行化SerializationWord文档格式.docx_第1页
第1页 / 共15页
串行化SerializationWord文档格式.docx_第2页
第2页 / 共15页
串行化SerializationWord文档格式.docx_第3页
第3页 / 共15页
串行化SerializationWord文档格式.docx_第4页
第4页 / 共15页
串行化SerializationWord文档格式.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

串行化SerializationWord文档格式.docx

《串行化SerializationWord文档格式.docx》由会员分享,可在线阅读,更多相关《串行化SerializationWord文档格式.docx(15页珍藏版)》请在冰豆网上搜索。

串行化SerializationWord文档格式.docx

if(!

file.Open(filename,CFile:

modeRead,&

fe))

{

fe.ReportError();

return;

}

//构建CArchive对象

CArchivear(&

file,CArchive:

load);

ar>

obj1>

obj2>

obj3...>

objn;

ar.Flush();

//读完毕,关闭文件流

ar.Close();

file.Close();

使用CArchive对对象进行写操作的过程如下:

//示例代码3

modeWrite|CFile:

modeCreate,&

ar<

obj1<

obj2<

obj3...<

//写完毕,关闭文件流

可见,对于一个文件而言,如果文件内对象的排列顺序是固定的,那么对于文件读和写从形式上只有使用的运算符的不同。

在MFC的框架/文档/视图结构中,一个文档的内部对象的构成往往是固定的,这种情况下,写到文件中时对象在文件中的布局也是固定的。

因此CDocument利用其基类CObject提供的Serilize虚函数,实现自动文档的读写。

当用户在界面上选择文件菜单/打开文件(ID_FILE_OPEN)时,CWinApp派生类的OnFileOpen函数被自动调用,它通过文档模板创建(MDI)/重用(SDI)框架、文档和视图对象,并最终调用CDocument:

OnOpenDocument来读文件,CDocument:

OnOpenDocument的处理流程如下:

//示例代码4

BOOLCDocument:

OnOpenDocument(LPCTSTRlpszPathName)

if(IsModified())

TRACE0("

Warning:

OnOpenDocumentreplacesanunsaveddocument.\n"

);

CFileExceptionfe;

CFile*pFile=GetFile(lpszPathName,

CFile:

modeRead|CFile:

shareDenyWrite,&

fe);

if(pFile==NULL)

{

ReportSaveLoadException(lpszPathName,&

fe,

FALSE,AFX_IDP_FAILED_TO_OPEN_DOC);

returnFALSE;

}

DeleteContents();

SetModifiedFlag();

//dirtyduringde-serialize

CArchiveloadArchive(pFile,CArchive:

load|CArchive:

bNoFlushOnDelete);

loadArchive.m_pDocument=this;

loadArchive.m_bForceFlat=FALSE;

TRY

CWaitCursorwait;

if(pFile->

GetLength()!

=0)

Serialize(loadArchive);

//loadme

loadArchive.Close();

ReleaseFile(pFile,FALSE);

CATCH_ALL(e)

ReleaseFile(pFile,TRUE);

DeleteContents();

//removefailedcontents

TRY

{

ReportSaveLoadException(lpszPathName,e,

FALSE,AFX_IDP_FAILED_TO_OPEN_DOC);

}

END_TRY

DELETE_EXCEPTION(e);

END_CATCH_ALL

SetModifiedFlag(FALSE);

//startoffwithunmodified

returnTRUE;

同样,当用户选择菜单文件/文件保存(ID_FILE_SAVE)或者文件/另存为...(ID_FILE_SAVEAS)时,通过CWinApp:

OnFileSave和CWinApp:

OnFileSaveAs最终调用CDocument:

OnSaveDocument,这个函数处理如下:

//示例代码5

OnSaveDocument(LPCTSTRlpszPathName)

CFile*pFile=NULL;

pFile=GetFile(lpszPathName,CFile:

modeCreate|

modeReadWrite|CFile:

shareExclusive,&

TRUE,AFX_IDP_INVALID_FILENAME);

CArchivesaveArchive(pFile,CArchive:

store|CArchive:

saveArchive.m_pDocument=this;

saveArchive.m_bForceFlat=FALSE;

Serialize(saveArchive);

//saveme

saveArchive.Close();

TRUE,AFX_IDP_FAILED_TO_SAVE_DOC);

//backtounmodified

//success

从前面两段代码可以看出,文件读和文件写的结构基本相同,并且最终都调用了CObject:

Serialize函数完成对文档自己的读和写(参见注释中的saveme和loadme)。

对于用AppWizard自动生成的MDI和SDI,系统自动生成了这个函数的重载实现,缺省的实现为:

//示例代码6

voidCMyDoc:

Serialize(CArchive&

ar)

if(ar.IsStoring())

//TODO:

addstoringcodehere

else

addloadingcodehere

如果一个对VC非常熟悉的人,喜欢手工生成所有的代码(当然这是非常浪费时间也是没有必要的),那么他提供的CDocument派生类也应该实现这个缺省的Serialize函数,否则,系统在文件读写时只能调用CObject:

Serialize,这个函数什么都不做,当然也无法完成对特定对象的文件保存/载入工作。

当然,用户也可以截获ID_FILE_OPEN等菜单,实现自己的文件读写功能,但是这样的代码将变得非常烦琐,也不容易阅读。

回到CMyDoc:

Serialize函数。

这个函数通过对ar对象的判断,决定当前是在读还是在写文件。

由于AppWizard不知道你的文档是干什么的,所以它不会给你添加实际的文件读写代码。

假设你的文档中有三个对象m_Obj_a,m_Obj_b,m_Obj_c,那么实际的代码应该为:

//示例代码7

ar<

m_Obj_a<

m_Obj_b<

m_Obj_c;

ar>

m_Obj_a>

m_Obj_b>

可串行化对象(SerializableObject)

要利用示例代码7中的方式进行文件I/O的一个基本条件是:

m_Obj_a等对象必须是可串行化的对象。

一个可串行化对象的条件为:

∙这个类从CObject派生)

∙该类实现了Serialize函数

∙该类在定义时使用了DECLARE_SERIAL宏

∙在类的实现文件中使用了IMPLEMENT_SERIAL宏

∙这个类有一个不带参数的构造函数,或者某一个带参数的构造函数所有的参数都提供了缺省参数

这里,可串行化对象条件中没有包括简单类型,对于简单类型,CArchive基本都实现了运算符<

的重载,所以可以直接使用串行化方式进行读写。

从CObject类派生

串行化要求对象从CObject派生,或者从一个CObject的派生类派生。

这个要求比较简单,因为几乎所有的类(不包括CString)都是从CObject派生的,因此对于从MFC类继承的类都满足这个要求。

对于自己的数据类,可以指定它的基类为CObject来满足这个要求。

实现Serialize函数

Serialize函数是对象真正保存数据的函数,是整个串行化的核心。

其实现方法和CMyDoc:

Serialize一样,利用CArchive:

IsStoring和CArchive:

IsLoading判断当前的操作,并选择<

来保存和读取对象。

使用DECLARE_SERIAL宏

DECLARE_SERIAL宏包括了DECLARE_DYNAMIC和DECLARE_DYNCREATE功能,它定义了一个类的CRuntimeClass相关信息,并实现了缺省的operator>

重载。

实现了该宏以后,CArchive就可以利用ReadObject和WriteObject来进行对象I/O,并能够在事先不知道类型的情况下从文件中读对象。

使用IMPLEMENT_SERIAL

DECLARE_SERIAL宏和IMPLEMENT_SERIAL宏必须成对出现,否则DECLARE_SERIAL宏定义的实体将无法实现,最终导致连接错误。

缺省构造函数

这是CRuntimeClass:

CreateObject对对象的要求。

特殊情况

∙只通过Serialize函数对对象读写,而不使用ReadObject/WriteObject和运算符重载时,前面的可串行化条件不需要,只要实现Serialize函数即可。

∙对于现存的类,如果它没有提供串行化功能,可以通过使用重载友元operator<

和operator>

来实现。

例子

假设需要实现一个几何图形显示、编辑程序,支持可扩展的图形功能。

这里不想讨论具体图形系统的实现,只讨论图像对象的保存和载入。

基类CPicture

每个图形对象都从CPicture派生,这个类实现了串行化功能,其实现代码为:

//头文件picture.h

#if!

defined(__PICTURE_H__)

#define__PICTURE_H__

#if_MSC_VER>

1000

#pragmaonce

#endif//_MSC_VER>

constintTYPE_UNKNOWN=-1;

classCPicture:

publicCObject

intm_nType;

//图形类别

DECLARE_SERIAL(CPicture)

public:

CPicture(intm_nType=TYPE_UNKNOWN):

m_nType(m_nType){};

intGetType()const{returnm_nType;

};

virtualvoidDraw(CDC*pDC);

voidSerialize(CArchive&

ar);

};

#endif

//cpp文件picture.cpp

#include"

stdafx.h"

picture.h"

#ifdef_DEBUG

#definenewDEBUG_NEW

#undefTHIS_FILE

staticcharTHIS_FILE[]=__FILE__;

voidCPicture:

Draw(CDC*pDC)

//基类不实现绘图功能,由派生类实现

Serialize(CArchive&

if(ar.IsLoading())

m_nType;

}else{

注意:

由于CRuntimeClass要求这个对象必须能够被实例化,因此虽然Draw函数没有任何绘图操作,这个类还是没有把它定义成纯虚函数。

对象在CDocument派生类中的保存和文件I/O过程

为了简化设计,在CDocument类派生类中,采用MFC提供的模板类CPtrList来保存对象。

该对象定义为:

protected:

CTypedPtrListm_listPictures;

由于CTypedPtrList和CPtrList都没有实现Serialize函数,因此不能够通过ar<

m_listPictures和ar>

m_listPictures来序列化对象,因此CPictureDoc的Serialize函数需要如下实现:

voidCTsDoc:

POSITIONpos;

pos=m_listPictures.GetHeadPosition();

while(pos!

=NULL)

m_listPictures.GetNext(pos);

RemoveAll();

CPicture*pPicture;

do{

try

pPicture;

TRACE("

ReadObject%d\n"

pPicture->

GetType());

m_listPictures.AddTail(pPicture);

catch(CException*e)

e->

Delete();

break;

}while(pPicture!

=NULL);

m_pCurrent=NULL;

SetModifiedFlag(FALSE);

实现派生类的串行化功能

几何图形程序支持直线、矩形、三角形、椭圆等图形,分别以类CLine、CRectangle、CTriangle和CEllipse实现。

以类CLine为例,实现串行化功能:

1.从CPicture派生CLine,在CLine类定义中增加如下成员变量:

2.CPointm_ptStart,m_ptEnd;

3.在该行下一行增加如下宏:

4.DECLARE_SERIAL(CLine)

5.实现Serialize函数

6.voidCLine:

7.{

8.CPicture:

Serialize(ar);

9.if(ar.IsLoading())

10.{

11.ar>

m_ptStart.x>

m_ptStart.y>

m_ptEnd.x>

m_ptEnd.y;

12.}else{

13.ar<

m_ptStart.x<

m_ptStart.y<

m_ptEnd.x<

14.}

15.}

16.在CPP文件中增加

17.IMPLEMENT_SERIAL(CLine,CPicture,TYPE_LINE);

这样定义的CLine就具有串行化功能,其他图形类可以类似定义。

附注

本文仓促草就,不足之处在所难免。

请发现谬误者给我来信说明,谢谢。

最新评论[发表评论][文章投稿]

查看所有评论

推荐给好友

打印

罗恩大哥,你好,我在实际变成中想自动载入上次的文件有什么好的方法吗?

(yangqifengfan发表于2005-3-258:

24:

00)

 

写的不错。

(徐明刚发表于2004-10-1212:

27:

罗恩大哥,你好,我是vc++初学者,(以前看过windows程序设计(第5版),

机工社的《c++精髓 

软件工程方法》),

最近在看《深入浅出MFC》,第8章时,里边也说到了Serialize,我不是很懂,

我看你的个人专栏里边看了串行化(Serialization)这篇文章也提到了,

你能顺便给我解释一下吗Serialize

在你的示例代码7中有 

ar 

m_Obj_a 

这里operator 

是不是调用

_AFX_INLINE 

CArchive&

AFXAPI 

operator>

(CArchive&

ar,CObject*&

pOb) 

如果是,那么IMPLEMENT_SERIAL宏 

展开后的

ar, 

class_name* 

&

在哪里用到?

还有为什么IMPLEMENT_SERIAL宏 

有CArchive&

没有CArchive&

operator<

在示例7中出现ar 

m_Obj_a(yckyck2001发表于2004-7-1114:

03:

我就把你当成我现在的目标了(弃卒发表于2004-6-1415:

25:

将内存指针系列化可不是个好主意(m_listPictures这一段)(jiangsanhuo发表于2004-2-49:

04:

最明显的错误是:

pPicture;

之前没有为pPicture分配内存:

pPicture 

new 

CPicture;

(eeixy2000发表于2003-12-2719:

12:

唉,希望这个文档不要被大家看成是教人家怎么绘图的:

((阿荣发表于2003-11-2013:

51:

建议看看vckbase上面得EastDraw程序,该文章中说得所有内容都可以从那个例子中找到,并且那个例子中还有undo功能得实现。

(coyer发表于2003-11-617:

14:

不错,建议以后多发表类似的文章!

(xiaojin发表于2003-11-423:

06:

如果发生版本升级,那么新版本的程序能不能兼容旧版本本来就需要看代码怎么设计,这种情况下,不使用串行化一样不能达到目的。

有两个方法可以解决这个问题:

1)根据扩展名不同实现不同的Serialize功能,可以在S

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1