实验9文件操作.docx
- 文档编号:7170310
- 上传时间:2023-01-21
- 格式:DOCX
- 页数:14
- 大小:173.19KB
实验9文件操作.docx
《实验9文件操作.docx》由会员分享,可在线阅读,更多相关《实验9文件操作.docx(14页珍藏版)》请在冰豆网上搜索。
实验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类配合使用来完成文件的读写操作?
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 实验 文件 操作