11. return ar;
12. }
13. friend CArchive& AFXAPI operator >>(CArchive& ar, test_st& info)
14. {
15. //读取
16. ar>>info.valueX>>info.valueY;
17. return ar;
18. }
19.}TEST;
D.使用Read和Write可实现指定数据长度的数据写入/读取,这里的数据长度指的是字节数。
使用WriteString可写入字符串,ReadString可读出一行字符。
注意这里WriteString并不是写入一行字符串,WriteString写入的字符串时不会写入'\0',也不会自动写入'\n'。
下面是来自MSDN的一个例子,相信能说明问题。
[cpp] viewplaincopy
1.CFile myFile("myfile", CFile:
:
modeCreate | CFile:
:
modeReadWrite);
2.CString str1="String1", str2="String2", str;
3.
4.// Create a storing archive.
5.CArchive arStore(&myFile, CArchive:
:
store);
6.
7.// Write str1 and str2 to the archive
8.arStore.WriteString( str1 );
9.arStore.WriteString( "\n" );
10.arStore.WriteString( str2 );
11.arStore.WriteString( "\n" );
12.
13.// Close the storing archive
14.arStore.Close();
15.
16.// Create a loading archive.
17.myFile.SeekToBegin();
18.CArchive arLoad(&myFile, CArchive:
:
load);
19.
20.// Verify the two strings are in the archive.
21.arLoad.ReadString( str );
22.ASSERT( str == str1 );
23.arLoad.ReadString( str );
24.ASSERT( str == str2 );
E.IsLoading和IsStoring函数常用来判断是读取还是写入。
Close函数用于切断与CFile对象的关联,在这之前会自动调用Flush将缓冲区数据写入存储媒质中。
F.在程序中,如果没有调用函数Flush(),那么真正将数据写入到物理磁盘是在调用函数Close()关闭时。
因此,一些重要的数据需要使用Flush()函数立即写入文件,以防丢失。
(2)类对象的读写
A.利用CArchive保存/加载一个类对象,则此类必须支持串行化。
B.自定义串行化类的五个步骤:
①继承CObject类;
②重载CObject类的Serialize成员函数;
③在类的.h文件中,进行串行化的声明:
DECLARE_SERIAL(类名);
④定义一个无参数的构造函数;
⑤在类的.cpp文件中,进行声明:
IMPLEMENT_SERIAL(类名,CObject,版本号)
C.在自定义的类的Serialize成员函数下,使用上述
(1)中的方法,保存/加载基本数据类型。
如下。
在需要文件操作的地方,直接调用该函数即可。
[cpp] viewplaincopy
1.void CXXXX:
:
Serialize(CArchive &ar)
2.{
3. if (ar.IsStoring())
4. { //保存
5. //Add code....
6. }
7. else
8. { //读取
9.
10. //Add code...
11. }
12.}
D.利用此方法,可实现数据的分布式保存。
通常在文档视图编程时,我们在文档类下定义数据对象,然后在其Serialize函数下实现数据的保存/加载即可。
通常我们会定义一个容器,用来存放数据。
例如,在我的项目中,我使用了
CTypedPtrListm_DataList;
这是一个链表,里面元素为CObject类对象的指针,当我们自定义了支持串行化的类后,就可以把数据加入到这个链表中,很方便的实现数据管理和存储。
MFC总结
(一):
MFC中文件操作、查找与选择总结(3)
(三)为保存文件选择路径
A.使用SHBrowseForFolder函数创建一个对话框,用于选择路径。
其原型为
LPITEMIDLISTSHBrowseForFolder(LPBROWSEINFOlpbi)
其中,返回值是一个指针,一个项目标识符列表,如果用户选择了取消的话,则返回NULL。
输入参数lpbi为BROWSEINFO结构体指针,用于设置对话框的一些属性,其结构分析如下。
[cpp] viewplaincopy
1.typedef struct _browseinfo {
2. HWND hwndOwner; //路径选择对话框的父窗口句柄,可设为this->m_hWnd
3. LPCITEMIDLIST pidlRoot; //浏览时的初始根目录,设为NULL时为桌面目录
4. LPTSTR pszDisplayName; //用于保存用户选中的路径
5. LPCTSTR lpszTitle; //对话框标题
6. UINT ulFlags; //指定对话框的一些特性,为一些值的组合
7. BFFCALLBACK lpfn; //处理事件的回调函数,一般设为NULL
8. LPARAM lParam; //应用程序传给回调函数的参数,一般设为NULL
9. int iImage; //保存被选取的文件夾的图片索引,一般设为NULL
10.} BROWSEINFO, *PBROWSEINFO, *LPBROWSEINFO;
B.当选择了一个路径后,使用函数SHGetPathFromIDList提取出选择的路径。
其原型为
BOOL SHGetPathFromIDList(LPCITEMIDLIST pidl,LPTSTR pszPath)
其中,输入参数pidl为上述SHBrowseForFolder的返回值,输出参数pszPath为所选择路径。
调用成功则返回TRUE。
C.应用示例。
[cpp] viewplaincopy
1.//更改文件保存路径
2.void CTestDlg:
:
OnPathselect()
3.{
4. //调用两个函数SHBrowseForFolder,SHGetPathFromIDList
5. LPITEMIDLIST pID; //定义第一个函数的返回值
6. BROWSEINFO lpbi; //定义其输入值
7. char path[MAX_PATH]; //保存路径
8. //为lpbi赋值
9. memset(&lpbi,0,sizeof(BROWSEINFO));
10. lpbi.hwndOwner=this->m_hWnd; // 父窗口句柄
11. lpbi.lpszTitle="请选择保存路径"; // 显示位于对话框左上部的标题
12. lpbi.ulFlags=BIF_EDITBOX ; // 指定对话框的外观和功能的标志
13. pID=SHBrowseForFolder(&lpbi); //选择路径,获取ID
14. if(pID!
=NULL)
15. { //如果成功得到
16. SHGetPathFromIDList(pID,path); //获取路径
17. GetDlgItem(IDC_PATH)->SetWindowText(path); //显示路径
18. }
19.}
(四)选择文件
A.使用CFileDialog类,定义一个对象。
其构造函数如下。
[cpp] viewplaincopy
1.CFileDialog(
2. BOOL bOpenFileDialog, //为TRUE表示“打开”对话框,为FALSE表示“保存”对话框
3. LPCTSTR lpszDefExt = NULL, //指定默认的文件扩展名
4. LPCTSTR lpszFileName = NULL, //指定默认的文件名
5. DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, //指定一些风格
6. LPCTSTR lpszFilter = NULL, //指定可供选择的文件类型和相应的扩展名
7. CWnd* pParentWnd = NULL, //父窗口指针
8. DWORD dwSize = 0
9.);
B.文件类型和扩展名的书写格式(参数lpszFilter)
①文件类型说明和扩展名之间用|分割;
②同种文件类型的扩展名之间用;分割;
③每种文件类型之间用|分割;
④末尾用||指明
例如,“DataFiles(*.xlc;*xls)|*.xlc;*.xls|AllFiles(*.*)|*.*||”。
其中,蓝色表示文件类型说明,粉色表示扩展名。
C.定义CFileDialog类对象后,可使用DoModal函数来产生对话框,选择文件。
在对话框“确定”返回后,可使用下列函数获取路径和文件名。
主要函数为:
GetPathName,GetFileName,GetExtName,GetFileTile等。
D.应用该类成员变量m_ofn可设置初始目录。
如dlg.m_ofn.lpstrInitialDir=_T("C:
\\")。
E.应用函数GetStartPosition和GetNextPathName可实现选择多个文件的情况。
F.一个示例,用于选择单个文件。
[cpp] viewplaincopy
1.//选择发送的文件
2.void CTestDlg:
:
OnSelectfile()
3.{
4. CString str;
5. CFileDialog dlg(TRUE,NULL,NULL,NULL,
6. "DATA Files(*.dat;*.txt)|*.dat;*.txt|All Files(*.*)|*.*||",this);//定义对象
7. if(dlg.DoModal()==IDOK)
8. {
9. str=dlg.GetPathName(); //获取文件名
10. }
11.
12. UpdateData(TRUE);
13. m_nFilePath=str; //显示路径
14. UpdateData(FALSE);
15.}
(五)在指定目录下查找文件
A.使用CFileFind类可查找指定目录下的文件,涉及的函数有查找函数FindFile和FindNextFile,获取文件属性函数和判断文件属性函数,详见MSDN。
B.对于查找函数,
[cpp] viewplaincopy
1.BOOL FindFile(
2. LPCTSTR pstrName = NULL, //查找的文件说明
3. DWORD dwUnused = 0 //必须为0
4.);
5.virtual BOOL FindNextFile(); //返回非0表示还有符合条件的文件,返回0表示是最后一个符合条件的文件
需要查找的文件名pstrName可设为以下几种:
"E:
\\VC++\\example.txt" “E:
\\VC++\\ex*.txt” "E:
\\VC++\\*.*"
C.一个示例。
[cpp] viewplaincopy
1.CFileFind finder;
2.BOOL bResult = finder.FindFile(_T("C:
\\te*.dat"));
3.while(bResult)
4.{
5. bResult = finder.FindNextFile();
6. cout<<(LPCTSTR)finder.GetFileName()<7.}
(六)获取可执行程序所在的目录
A.对于API函数GetCurrentDirectory虽然从字面意思上看是获取当前目录,其实获取的并不是.exe执行文件所在的目录,而是其上一级目录。
例如,程序安装在桌面上,我们通过该函数获取的路径是C:
\DocumentsandSettings\Administrator,而不是C:
\DocumentsandSettings\Administrator\桌面。
B.如需获取程序执行时所在的目录,可使用另外一个API函数:
GetModuleFileName。
采用该函数可获取程序当前执行的文件名(包含完整的路径),然后结合_tsplitpath函数可分解出路径、文件名、扩展名,再根据需要进行组合。
C.下面是本人在程序中常使用的一个函数:
[cpp] viewplaincopy
1.//获取当前程序运行目录
2.CString GetCurrentDir()
3.{
4. TCHAR szFull[_MAX_PATH]; //完整路径
5. TCHAR szDrive[_MAX_DRIVE]; //盘符
6. TCHAR szDir[_MAX_DIR]; //路径
7.
8. //获取程序当前执行文件名(包含完整路径)
9. GetModuleFileName(NULL, szFull, _MAX_PATH);
10. _tsplitpath(szFull, szDrive, szDir, NULL, NULL);
11.
12. _tcscpy(szFull, szDrive); //盘符
13. _tcscat(szFull, szDir); //路径
14.
15. return CString(szFull); //返回路径
16.}
(七)关于access函数的应用
A.对于access函数知道的人不多,这个函数主要可以用来确定文件或文件夹的访问权限或是否存在。
其原型如下:
[html] viewplaincopy
1.int _access(
2. const char *path,
3. int mode
4.);
B.参数path用于指定文件或文件夹路径,mode用于指定模式,其有如下四种:
mode值
要判断的模式
00
判断是否存在
02
判断是否有只写权限
04
判断是否有只读权限
06
判断是否有读和写权限
当path指定为文件时,mode可设置上述四个任意的值;当path指定为文件夹时,只能判断其是否存在。
C.使用时,必须包含io.h头文件。
D.本人曾经使用该函数来判断某文件夹下的某文件是否存在,以确定作相应的处理。
全文完。
。
。