实验9文件操作.docx

上传人:b****6 文档编号:7170310 上传时间:2023-01-21 格式:DOCX 页数:14 大小:173.19KB
下载 相关 举报
实验9文件操作.docx_第1页
第1页 / 共14页
实验9文件操作.docx_第2页
第2页 / 共14页
实验9文件操作.docx_第3页
第3页 / 共14页
实验9文件操作.docx_第4页
第4页 / 共14页
实验9文件操作.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

实验9文件操作.docx

《实验9文件操作.docx》由会员分享,可在线阅读,更多相关《实验9文件操作.docx(14页珍藏版)》请在冰豆网上搜索。

实验9文件操作.docx

实验9文件操作

实验9文件操作

实验目的

1、掌握文档串行化的原理

2、掌握用CFile类实现文件的读写操作

3、掌握文件的输入/输出流

实验内容

主要讲述文件操作的有关知识,内容包括文档串行化、CFile类、内存稳健类和文件的输入/输出,重点讲述了文件操作实现的两种方法——串行化和CFile类。

文件管理是操作系统的一个重要组成部分,而文件操作就是通过用户编程实现文件管理的一种手段。

基本概念:

串行化、CArchive类、CFile类、文件的读写操作、文件的管理、文件异常、文件对话框、CMemFile类、CSharedFile类、文件输入/输等,见PPT文档。

在MFCAppWizard生成MFCAppWizard[exe]程序框架时,如果在MFCAppWizard—Step1对话框中选择了Document/Viewarchitecturesupport,将会在自动生成的程序中支持CDocument派生类的Serialize成员函数的操作。

在MFCAppWizard—Step4of6对话框中有Advanced按钮,弹出AdvancedOptions对话框,如下图:

输入项

信息说明

Fileextension

文件扩展名

FiletypeID

注册表中等级的文档类型项目的标签文字

Mainframecaption

应用程序的标题

Doctypename

文档类型名,限制6个字母,多文档程序用这个名字加上数字序号作为新建文件的文件名

Filtername

文档描述过滤符

Filenewname(shortname)

多个文档模版时新建对话框中显示的该文档文字信息文件,限制15个字符

Filetypename(longname)

注册表记录的文件类型名,限制40个字母

例创建统计年度产值程序,实现文件操作。

详细步骤如下:

1、创建一个AppWizard[exe]类型的MDI工程,名称为ex101。

在MFCAppWizard—Step1对话框中选择Document/Viewarchitecturesupport如上第一图。

为了实现视图类的界面,使用了ActiveXControls,所以要在MFCAppWizard—Step3of6对话框中选择ActiveXControls,以使MFC支持ActiveX;否则,程序将不能正常运行。

在MFCAppWizard—Step4of6对话框中,单击Advanced按钮,设置文档类型,如下图

在MFCAppWizard—Step6of6对话框中,将CEx101View视图类的基类选择为CFormView,单击OK完成。

2、设计CEx101View类的界面。

打开ResourceView双击Dialog中的IDD_Ex101_FORM项,可以编辑CEx101View使用的对话框资源。

按照下图的排列,增加下表中的控件。

控件含义

ID

类型

属性

年份

IDC_YEAR

EditBox

选中Styles—Number

改变年份Spin

IDC_SPIN_YEAR

Spin

默认

月份

IDC_MONTH

ComboBox

Data输入“一月”到“十二月”,Styles—Type去掉Sort

当月产值

IDC_MON_PRO

EditBox

选中Styles—Number

当月备注

IDC_MON_MEM

EditBox

默认

比上月增长率

IDC_RISERATE

StaticText

删除Caption

全年产值

IDC_YEAE_PRO

FormLabel

删除Caption,黑体14

在输入一月到十二月时,使用Ctrl+Enter换行。

窗口上的其他文字信息是StaticText控件,设定好位置后写上文字即可。

添加全年产值控件的方法是:

在编辑对话框的窗口上,按鼠标右键选择InsertActiveXControls,在弹出的对话框上添加MicrosoftForms2.0Label控件,选择其属性,可以设置较为美观的字体、颜色。

3、给CEx101Doc类添加成员变量。

给CEx101Doc类添加记录各月产值、备注、年份等的变量,可以使用鼠标右键弹出菜单中的AddMemberVariable项,添加部分变量并定位到源代码中变量定义处,继续添加下列代码:

public:

struct{

intnProduct;//月份产量

charsNote[50];//备注

}m_Month[12];//记录各月信息

intm_nTotalProduct;//年总产量

intm_nYear;//年份

在CEx101Doc类的构造函数中对这些变量进行初始化:

CEx101Doc:

:

CEx101Doc()

{

m_nYear=2005;

m_nTotalProduct=0;

for(inti=0;i<12;i++)

{

m_Month[i].nProduct=0;

m_Month[i].sNote[0]=NULL;

}

}

4、给CEX101View类添加成员变量。

利用类向导给CEX101View类添加以下成员变量。

控件ID

类型

成员变量

说明

IDC_YEAR

int

m_nYear

年份

IDC_MONTH

CComboBox

m_ctrlMonthList

选择月份组合框

IDC_MON_PRO

int

m_nMonPro

当月产值

IDC_MON_MEM

CString

m_strMonMem

当月备注

IDC_RISERATE

CString

m_strRiseRate

增长率字符串

IDC_YEAE_PRO

CLabelControl

m_YearPro

年总产值

注意:

CLabelControl类,是在类向导中为ActiveX控件IDC_YEAE_PRO增加变量时自动生成的,它实现了对这个控件的基本控制,在此没有改动它的代码。

另外在视图类中添加一个记录当前月份的整数变量。

Private:

intm_nCurrentMonth;

5、实现CEX101View类成员函数。

用类向导增加响应用户输入的成员函数。

因为采用CFormView基类,关闭文档窗口时来不及获取最近数据,所以这些输入控件都响应的是EN_CHANGE消息,数据一有变化就记录下来。

A、初始化CEX101View类构造函数。

CEx101View:

:

CEx101View()

:

CFormView(CEx101View:

:

IDD)

{

m_nYear=0;

m_nMonPro=0;

m_strMonMem=_T("");

m_strRiseRate=_T("");

m_nCurrentMonth=0;//0代表1月

//}}AFX_DATA_INIT

}

B、初始化更新函数OnInitUpdate()完成初始化时的一些设置工作。

voidCEx101View:

:

OnInitialUpdate()

{

CFormView:

:

OnInitialUpdate();

ResizeParentToFit();

CEx101Doc*pDoc=GetDocument();

m_nYear=pDoc->m_nYear;//获取文档中的年份

m_ctrlMonthList.SetCurSel(0);//选择一月

m_nCurrentMonth=0;//当前月是一月

m_nMonPro=pDoc->m_Month[0].nProduct;//一月产值

m_strMonMem=pDoc->m_Month[0].sNote;//一月备注

m_strRiseRate="第一月无此值";

CStringstr;

str.Format("%d",pDoc->m_nTotalProduct);

m_YearPro.SetCaption(str);

//调用CLableControl设置标题函数显示年总产值

UpdateData(false);

}

C、添加当月备注函数OnChangeMonMem()。

使用类向导在CEx101View类中增加成员函数,用于响应输入当月备注控件IDC_MON_MEM的EN_CHANGE消息,其代码如下:

voidCEx101View:

:

OnChangeMonMem()

{

CEx101Doc*pDoc=GetDocument();

UpdateData();//获取最新输入数据

//和文档中的数据比较,看是否有变化

if(strcmp(pDoc->m_Month[m_nCurrentMonth].sNote,m_strMonMem))

{

//记录新数据

strcpy(pDoc->m_Month[m_nCurrentMonth].sNote,m_strMonMem);

pDoc->SetModifiedFlag();//设置文档改变标志

}

}

D、添加当月产值OnChangeMonPro()函数。

使用类向导在CEx101View类中增加成员函数,用于响应输入当月产值控件IDC_MON_PRO的EN_CHANGE消息,其代码如下:

voidCEx101View:

:

OnChangeMonPro()

{

CEx101Doc*pDoc=GetDocument();

UpdateData();//获取输入的月份值

if(pDoc->m_Month[m_nCurrentMonth].nProduct!

=m_nMonPro)

{//比较判断数据是否改变,并改变总产值

pDoc->m_nTotalProduct+=m_nMonPro-pDoc->m_Month[m_nCurrentMonth].nProduct;

CStringstr;

str.Format("%d",pDoc->m_nTotalProduct);

m_YearPro.SetCaption(str);//显示总产值

pDoc->m_Month[m_nCurrentMonth].nProduct=m_nMonPro;

//记录当月产值,并计算增长率

if(m_nCurrentMonth==0)

m_strRiseRate="第一月无此值";

elseif(pDoc->m_Month[m_nCurrentMonth-1].nProduct==0)

m_strRiseRate="上月无产值";

else

m_strRiseRate.Format("%.2f%%",

(pDoc->m_Month[m_nCurrentMonth].nProduct-pDoc->m_Month[m_nCurrentMonth-1].nProduct)/(float)(pDoc->m_Month[m_nCurrentMonth-1].nProduct)*100);

pDoc->SetModifiedFlag();

UpdateData(false);

}

}

E、添加输入年份函数OnChangeYear()。

使用类向导增加CEx101View类的成员函数OnChangeYear(),响应输入年份控件IDC_YEAR的EN_CHANGE消息。

代码如下:

voidCEx101View:

:

OnChangeYear()

{

CEx101Doc*pDoc=GetDocument();

UpdateData();//获取最新输入

if(pDoc->m_nYear!

=m_nYear)

{//判断数据变化

pDoc->m_nYear=m_nYear;//记录到Doc中

pDoc->SetModifiedFlag();//设置修改标志

}

}

F、使用IDC_SPIN_YEAR微调控件改变年份。

使用类向导增加CEx101View类的成员函数OnDeltaposSpinYear(),响应改变年份的微调控件的UDN_DELTAPOS消息。

代码如下:

voidCEx101View:

:

OnDeltaposSpinYear(NMHDR*pNMHDR,LRESULT*pResult)

{

NM_UPDOWN*pNMUpDown=(NM_UPDOWN*)pNMHDR;

UpdateData();//获取最新输入

if((pNMUpDown->iDelta>0)&&(m_nYear>0))

m_nYear--;//减小年份并且不能小于0

elseif(pNMUpDown->iDelta<0)

m_nYear++;//增加年份

else//非法输入

{

AfxMessageBox("年份必须是非负数!

");

*pResult=0;

return;

}

GetDocument()->m_nYear=m_nYear;//文档记录年份

GetDocument()->SetModifiedFlag();

UpdateData(FALSE);

*pResult=0;

}

G、添加月份选择处理函数OnSelchangeMonth()。

利用类向导在CEx101View类中添加成员函数,响应月份控件IDC_MONTH的CBN_SELCHANGE消息。

代码如下:

voidCEx101View:

:

OnSelchangeMonth()

{

CEx101Doc*pDoc=GetDocument();

//获得当前选择月份并设置正确显示

m_nCurrentMonth=m_ctrlMonthList.GetCurSel();

//计算这个月增长率

if(m_nCurrentMonth==0)//是一月?

m_strRiseRate="第一月无此值!

";

elseif(pDoc->m_Month[m_nCurrentMonth-1].nProduct==0)

m_strRiseRate="上月无产值";

else//计算增长率

m_strRiseRate.Format("%.2f%%",(pDoc->m_Month[m_nCurrentMonth].nProduct-pDoc->m_Month[m_nCurrentMonth-1].nProduct)/

(float)(pDoc->m_Month[m_nCurrentMonth-1].nProduct)*100);

//获得当月产值和备注

m_nMonPro=pDoc->m_Month[m_nCurrentMonth].nProduct;

m_strMonMem=pDoc->m_Month[m_nCurrentMonth].sNote;

UpdateData(FALSE);

}

6、实现CEx101Doc类的串行化函数。

CEx101Doc类的串行化函数是MFC自动生成的,添加所需的代码,实现框架传递过来的CArchive对象对数据的读写操作。

在这个函数中给出了CArchive的“<<”和“>>”操作符、Read()和Write()函数的用法。

这里操作的文件就是在创建工程时确定的hjm文件。

从这里就可以知道hjm文件的格式。

voidCEx101Doc:

:

Serialize(CArchive&ar)

{

if(ar.IsStoring())//判断是否存储

{

//实现存储写的代码

ar<

ar<

for(inti=0;i<12;i++)//循环写入各月信息

{

ar<

ar.Write(m_Month[i].sNote,50);//这个月备注

}

}

else

{

//实现读出的代码

ar>>m_nYear;//读出年份

ar>>m_nTotalProduct;//读出总产值

intnTemp=0;

for(inti=0;i<12;i++)//读出各月信息

{

ar>>m_Month[i].nProduct;//这个月的产值

if(m_Month[i].nProduct<0)//纠正负值

m_Month[i].nProduct=-m_Month[i].nProduct;

nTemp+=m_Month[i].nProduct;//临时统计各月总产值

ar.Read(m_Month[i].sNote,50);//读出该月的备注信息

m_Month[i].sNote[49]=NULL;//确保字符串结束符存在

}

//进行检查工作

if(nTemp!

=m_nTotalProduct)//各月累计和总产值不符

{

AfxMessageBox("该报表文件中总产值与各月总和不符,\\n将总产值置为各月总和");

m_nTotalProduct=nTemp;

}

}

}

此时,程序可以编译、链接运行,已经可以对文档,即hjm文件进行新建、打开、保存等操作。

7、使用CStdioFile类。

使用串行化函数,可以完成对框架支持的文件的固定操作,但在需要实现一些特殊功能时,它就有些捉襟见肘了。

从上面实现的程序基础上继续来扩展功能:

用CStdioFile类实现从hjm数据文件中来生成txt文本文件。

1)添加菜单资源。

选择工作区资源视图,打开Menu项编辑IDR_YEARTYPE菜单。

打开“文件”菜单,在菜单项“另存为”和“打印”二者之间加入一个Separator菜单项,然后在加入“生成文本报表”菜单项;ID为ID_CREATE_TEXT,Caption为“生成文本报表”。

2)生成文本报表函数,利用类向导在CEx101Doc类中增加响应ID_CREATE_TEXT的COMMAND消息的成员函数,即完成当前打开的年度产值报表hjm文件生成一个txt文件。

在这里使用使用CFile的派生类CStdioFile类来完成。

CStdioFile的流方式文本操作对此使用较为方便。

该函数还演示了对于文件名信息的一些操作技巧。

voidCEx101Doc:

:

OnCreateText()

{

CStringstr;

CStringfilename=GetPathName();//获取该文档当前的hjm名

if(filename.IsEmpty())//如果空

filename=GetTitle()+".txt";//从标题获得

else

filename=filename.Left(filename.GetLength()-3)+"txt";

CStdioFilefile;

//用CStdioFile创建一个txt文件,注意使用的文件操作标志

if(file.Open(filename,CFile:

:

modeCreate|CFile:

:

modeWrite|CFile:

:

typeText)==0)

{

str="创建文件"+filename+"失败!

";

AfxMessageBox(str);//创建失败

return;

}

//写文本文件内容

str.Format("%d年产值报告\n\n",m_nYear);

file.WriteString(str);

str.Format("总产值:

%d元\n\n",m_nTotalProduct);

file.WriteString(str);

str.Format("月份:

产值:

单位(元)备注:

\n");

file.WriteString(str);

for(inti=0;i<12;i++)

{

str.Format("%4d%13d%s\n",i+1,m_Month[i].nProduct,m_Month[i].sNote);

file.WriteString(str);

}

//文件写完了,再做一些辅助工作

file.SetLength(file.GetPosition());

file.Close();

str="notepad"+filename;

WinExec(str,SW_SHOW);//用记事本打开

}

编译,链接并运行程序,打开“文件”文件菜单选择“生成文本报表”,观察运行效果。

 

思考和练习

1.什么是“串行化”?

VC++中是通过什么成员函数实现这一功能的?

2.CFile类的哪几个函数具备文件定位的功能?

3.怎样用CFile类和CFileDialog类配合使用来完成文件的读写操作?

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

当前位置:首页 > 表格模板 > 合同协议

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

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