第十三章、文档与串行化

13.1使用CArchive类对文件进行读/写操作

我们可以利用CArchive类将对象数据永久地保存到磁盘文件上,再次重启后仍然可以读取对象数据。让对象数据持久性的过程就称为串行化。

CArchive对象可以认为就是一种二进制流。首先在创建CArchive对象之前必须先建一个CFile类或其派生类对象;当构造一个CArchive对象后,就可以将它与CFile类或者其派生类对象相关联。应该注意,一个文件(CFile对象)只能与一个活动的存档对象相关联。CArchive类重载了<<和>>运算符。
CArchive( CFile* pFile, UINT nMode, int nBufSize = 4096, void* lpBuf = NULL );
第一个参数指向文件对象的指针;
第二个参数指定对象是用来加载的还是用来保存的;
第三个对象是内部文件缓冲区的大小;

打开11章Graphic工程,添加一个文件操作的子菜单,在该子菜单下添加写入文件和读取文件的菜单项,ID为IDM_FILE_WRITE和IDM_FILE_READ。并添加各自的命令消息响应函数。
然后再OnFileWrite函数添加:

void CGraphicView::OnFileWrite() 
{
 // TODO: Add your command handler code here
 //构造CFile文件对象
 CFile file("1.txt",CFile::modeCreate|CFile::modeWrite);
 //构造存档对象
 CArchive ar(&file,CArchive::store);
 int i=4;
 char ch='a';
 float f=1.3f;
 CString str("vc++");
 //保存数据
 ar<<i<<ch<<f<<str;
}

运行程序,然后发现Graphic程序下多了一个1.txt文件

然后在OnFileRead函数中实现文件的读取操作:

void CGraphicView::OnFileRead() 
{
 // TODO: Add your command handler code here
 //构造CFile文件对象
 CFile file("1.txt",CFile::modeRead);
 //构造存档对象
 CArchive ar(&file,CArchive::load);
 int i;
 float f;
 char ch;
 CString str;
 CString strResult;
 //读取数据
 ar>>i>>ch>>f>>str;
 strResult.Format("%d,%c,%f,%s",i,ch,f,str);
 MessageBox(strResult);
}

运行结果如图。
在这里插入图片描述

13.2MFC程序框架提供的文件新建功能

CGraphicDoc类有一个OnNewDocument函数,实际上,OnNewDocument函数是文件->新建命令处理的一部分,是由框架调用的一个虚函数。我们可以在CGraphicDoc类的OnNewDocument函数中修改文档的标题,这可以通过使用CDocument类中的成员函数:SetTitle。

BOOL CGraphicDoc::OnNewDocument()
{
 if (!CDocument::OnNewDocument())
  return FALSE;
 // TODO: add reinitialization code here
 // (SDI documents will reuse this document)
 SetTitle("vc++");
 return TRUE;
}

运行结果如图所示。
在这里插入图片描述

13.2.1IDR_MAINFRAME字符串资源

除了可以在OnNewDocument函数中修改文档标题之外,还可以通过IDR_MAINFRAME字符串资源来实现。如图。
在这里插入图片描述
该字符串是由\n字符分隔的7个子串,可以看到前两个\n之间没有任何内容,所以窗口标题显示无标题,可以在这两个\n之间来添加窗口标题。

一个资源ID可以标识多种资源,IDR_MAINFRAME不仅表示字符串资源,还表示菜单资源和图标资源。
对于我们看到的IDR_MAINFRAME字符串资源,可以利用文档模板类的成员函数:GetDocString来获取各个子串:
virtual BOOL GetDocString( CString& rString, enum DocStringIndex index ) const;
第一个参数是一个CString对象的引用;
第二个参数指定要查找字串的索引。

IDR_MAINFRAME第一个子串代表窗口的标题;第二个子串代表主窗口文档的标题,以及单击文件\保存菜单项时,默认的文档名;第三个子串指定的文档类型名出现在File\New对话框中;第四个子串与第五个子串连用,设置通配符过滤器,例如第四个子串"Text Files(*.txt)",第五个字串".txt"。

13.2.2OnNewDocument函数的调用过程

对于新建菜单项来说,应该有一个相应的菜单命令消息响应函数,但是OnNewDocument函数并不是一个消息响应函数,它是一个虚函数。因为OnNewDocument函数是虚函数,如果子类(CGraphicDoc)中存在重写这个函数,就会调用子类中的这个虚函数。
文件新建菜单命令->CWinApp::OnFileNew->CDocManager::OnFileNew->CSingleDocTemplate::OpenDocumentFile->CGraphicDoc::OnNewDocument

13.3文档串行化

13.3.1文档类的Serialize函数

我们可以看到文档类有一个Serialize函数:

void CGraphicDoc::Serialize(CArchive& ar)
{
 if (ar.IsStoring())
 {
  // TODO: add storing code here
 }
 else
 {
  // TODO: add loading code here
 }
}

该函数有一个参数,是CArchive类型。
单击文件打开和保存菜单项都会进入这个函数,这个函数就是文档类提供的用来保存和加载数据的函数。

下面将上述代码修改为:

void CGraphicDoc::Serialize(CArchive& ar)
{
 if (ar.IsStoring())
 {
  // TODO: add storing code here
  int i=4;
  char ch='a';
  float f=1.3f;
  CString str("vc++");
  ar<<i<<ch<<f<<str;
 }
 else
 {
  // TODO: add loading code here
  int i;
  float f;
  char ch;
  CString str;
  CString strResult;
  ar>>i>>ch>>f>>str;
  strResult.Format("%d,%c,%f,%s",i,ch,f,str);
  AfxMessageBox(strResult);
 }
}

运行程序,选择另存为菜单项,使用默认的文件保存名Graphic.txt。
然后在Graphic目录下就可以看到该文件。在不关闭程序的情况下,单击打开菜单项,选择刚刚保存的文件,单击打开,但是没有显示读取结果的消息框。
原因:在没有关闭程序的情况下,它认为你的数据已经在视类窗口中,所以就没有调用文档类的Serialize函数。

13.3.2MFC框架对Serialize函数的调用过程

文件打开菜单命令->CWinApp::OnFileOpen->CDocManager::OnFileOpen->CWinApp::OpenDocumentFile->CDocManager::OpenDocumentFile->CSingleDocTemplate::OpenDocumentFile->CDocument::OnOpenDocument->CGraphicDoc::Serialize

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

身影王座

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值