MFC文件操作

Posted roucheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MFC文件操作相关的知识,希望对你有一定的参考价值。

文件操作:二进制文件和文本文件的区别。二进制文件将数据在内存中存在的模式原封不动的搬到文件中,而文本文件是将数据的asc码搬到文件中。
首先做一个读写文件的菜单,在CxxView里响应
1.C的方式:
fwrite:
size:Item size in bytes 每次写多少个字节
count:Maximum number of items to be written ,总共写几次。

FILE *p;
p=fopen("c://1.txt","w");
fwrite("abc",1,4,p);
fclose(p);
由于我们打开文件后文件就被映射到内存中的缓存中,我们对文件所做的操作都是在内存中完成的,如果我们不关闭文件,则内存中对文件所做的修改就不会反映(保存)到硬盘中,除非你把当前一个应用程序关闭,这是会自动执行文件关闭的操作。
fflush可以在文件不关闭的情况下将一个流(缓冲区)当中的数据清空,这里的清空是把缓冲区的数据输出到硬盘。这样可以达到边写边输出的效果。
FILE* pFile=fopen("c://1.txt","w"); 
fwrite("何问起网",1,strlen("何问起网"),pFile);
//fclose(pFile);
fflush(pFile);
fwrite("how are you",1,strlen("何问起网"),pFile);
fflush(pFile);
fclose(pFile);
我们发现下一次的“h”是写在了上次的“心”后面了,这是因为,对于文件来说它有一个文件字符位置的指针,这个指针不同于文件的指针,是文件结构中这个char *_ptr;成员。当我们写完“心”字后,这个指针就在“心” 字后,所以下次写“h”的时候就是在“心”的后面写。如果想将第二句在“维”的前面输出,则要移动文件的位置指针,用fseek
FILE* pFile=fopen("c://1.txt","w"); 
fwrite("何问起网",1,strlen("何问起网"),pFile);
//fclose(pFile);
fflush(pFile); 
fseek(pFile,0,SEEK_SET);
fwrite("北京",1,strlen("北京"),pFile);
fflush(pFile);
fseek(pFile,0,SEEK_END);
CString str;
str.Format("文件大小:%d",ftell(pFile));
MessageBox(str);
fclose(pFile);
读文件
FILE* pFile=fopen("c://1.txt","r"); 
char buf[100];
fread(buf,1,100,pFile);//虽然读出的数据超出了实际字符串的长度,但输出时还是找’/0’
MessageBox(buf);
fclose(pFile);
出现了乱码,是因为输出文件的时候没有及时找到’/0’.将写文件的strlen改为sizeof
文件读写函数需要读写的时候将’/0’带上,它类似于printf和strlen等函数以’/0’作为函数结束表示。
乱码的解决也可以用
FILE* pFile=fopen("c://1.txt","r"); 
char buf[100];
fseek(pFile,0,SEEK_END);
long len=ftell(pFile);
rewind(pFile);
fread(buf,1,len,pFile);
buf[len]=0;
MessageBox(buf);
fclose(pFile);
第三种方法:
FILE* pFile=fopen("c://1.txt","r"); 
char buf[100];
memset(buf,0,100);//可以用任意的字符来填充这个内存块。
ZeroMemory(buf,100);// 只能用‘/0’字符来填充这个内存块。
fread(buf,1,100,pFile);
MessageBox(buf);
fclose(pFile);
2.C++的方式:#include "fstream.h"
写:
ofstream ofs("c://1.txt");
ofs.write("何问起网",sizeof("何问起网"));
ofs.close();//最好自己将文件关掉,不关也行,这个filebuf对象的析构函数为你关。
读:
ifstream ifs("c://1.txt");
char buf[100];
ifs.read(buf,100);
MessageBox(buf);
当我们写的代码改为                          
ofstream ofs("c://1.txt");
char str[3];
str[0]=\'a\';
str[1]=10;
str[2]=\'b\';
ofs.write(str,sizeof(str));
   ofs.seekp(0);
ofs.write("china",sizeof("china"));
发现此时默认按照文本写和读的时候,文件的大小不符。
这是因为在用文本文件方式读写的时候,碰到了asc码为10的字符,都将被转换,写文件的时候将10前面加上13写到了文件中,读文件读到13和10,将这两个字符换成一个10.注意在用ultraEdit看的时候不要转成DOS格式。
如果以二进制文件(ios::binary)进行读写的时候就没有这种问题存在。不做任何的转换。
C++的文件操作打开文件是在构造函数里完成,关闭文件是在析构函数里完成。
3. MFC的方式:
I. 写文件:
CFile f("c://1.txt",CFile::modeWrite|CFile::modeCreate);
f.Write("hello",5);
a.几个标志的作用:
  CFile::modeCreate:没有指定的文件就产生一个新文件,有就打开该文件,并将它裁剪到0;
  CFile::modeNoTruncate :打开文件时不裁剪到0;
b.写数据到文件末尾:
CFile f("c://1.txt",CFile::modeWrite|CFile::modeCreate|
CFile::modeNoTruncate);
      f.SeekToEnd();
f.Write("hello",5);
//file.Close();如果我不关闭的话,其析构函数会为我关闭。
II. 读文件:
CFile f("c://1.txt",CFile::modeRead);
char buf[10];
memset(buf,0,10);
f.read(buf,5);
MessageBox(buf);
III. 文件对话框:
保存对话框:

CFileDialog fdlg(false);
//fdlg.m_ofn.lpstrTitle="何问起造!";
fdlg.m_ofn.lpstrDefExt="txt";
fdlg.m_ofn.lpstrFilter="文本文件 (*.txt)/0*.txt/0所有文件 (*.*)/0*.*/0/0";
if(IDOK==fdlg.DoModal())
{
//MessageBox(fdlg.GetFileName());
CFile file(fdlg.GetFileName(),CFile::modeCreate|CFile::modeWrite);
file.Write("何问起网",sizeof("何问起网"));
file.Close();
}

打开对话框:

CFileDialog fdlg(true);
//fdlg.m_ofn.lpstrTitle="何问起造!";
fdlg.m_ofn.lpstrFilter="文本文件 (*.txt)/0*.txt/0所有文件 (*.*)/0*.*/0/0";
if(IDOK==fdlg.DoModal())
{  
CFile file(fdlg.GetFileName(),CFile::modeRead);
char buf[100];
file.Read(buf,100);
MessageBox(buf);
}
2. 文本文件和二进制文件的区别:
文件文件是一种特殊的二进制文件,当它遇到回车键10时,写入文件时会自动地在它的前面加一个13,而读出文件时遇到13 10 的组合时,又把它还原到10。而二进制文件就是把数据原封不动的写入文件,原封不动的再读取出来,没有文本文件的这种转换操作。
下面的代码演示了之间的这种区别:
  写入文件时:
   ofstream f("c://1.txt");
   char buf[3];
   buf[0]=\'a\';
   buf[1]=\'/n\';
   buf[2]=\'b\';
   f.write(buf,3);
读出文件时:
ifstream f("c://1.txt");
f.setmode(filebuf::binary);
char buf[5];
memset(buf,0,5);
f.read(buf,5);
CString str;
str.Format("%d,%d,%d,%d",buf[0],buf[1],buf[2],buf[3]);
MessageBox(str);
    在写入文件时不指定格式,文件将按文本格式存储,此时读出文件时指定二进制格式,读出的数据如下图:
      
如果注释f.setmode(filebuf::binary);语句,文件将按文本文件读出,如下图:

二、 注册表的操作
1. 读写win.ini文件:
使用API的GetProfileInt和WriteProfileString来实现一个保存窗口大小的例子。
在CMainFrame的
void CMainFrame::OnDestroy() 
{
CFrameWnd::OnDestroy();

// TODO: Add your message handler code here
CRect rect;
GetWindowRect(&rect);
CString str;
str.Format("%d",rect.Width());
WriteProfileString("窗口尺寸","宽度",str);
str.Format("%d",rect.Height());
WriteProfileString("窗口尺寸","高度",str);
}

在CMainFrame的
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
   return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
cs.cx=GetProfileInt("窗口尺寸","宽度",100);
cs.cy=GetProfileInt("窗口尺寸","高度",100);
return TRUE;
}

演示使用API的GetProfileString.对于它的第四个参数lpReturnedString需要添一个char*来返回。这里不能添CString对象来返回,这是一个特殊的地方。别的函数一般要char*的时候都可以用CString对象来代替。
这里我们用CString的GetBuffer来添这个char*。
A CString object consists of a variable-length sequence of characters.
因为一个字符串对象由一序列长度可变的字符组成。

Returns a pointer to the internal character buffer for the CString object. The returned LPTSTR is not const and thus allows direct modification of CString contents.
返回一个CString对象内部字符的缓冲区(字符数组)的指针,这个返回的指针不是一个常量的指针,因而允许直接修改指针所指向的CString对象的内容。这个指针和CString内部字符数组的地址是相等的。

If you use the pointer returned by GetBuffer to change the string contents, you must call ReleaseBuffer before using any other CString member functions.
如果你使用这个通过GetBuffer返回的指针改变了字符串的内容,你在使用CString其他成员函数之前必须调用ReleaseBuffer。

在CWinApp的InitInstance里
CString str;
::GetProfileString("窗口尺寸","高度","无值",str.GetBuffer(100),100);
AfxMessageBox(str);
下面测试CWinApp的WriteProfileString,GetProfileString。
对于WriteProfileString有段说明
· In Windows NT, the value is stored to a registry key.
· In Windows 3.x, the value is stored in the WIN.INI file. 
· In Windows 95, the value is stored in a cached version of WIN.INI
在CWinApp的InitInstance里
WriteProfileString("收藏","vc++","菜鸟");

CString str;
str=GetProfileString("收藏","vc++","无效值");
AfxMessageBox(str);
所以这里写的话是写到了HKEY_CURRENT_USER/Software/Local AppWizard-Generated Applications/MyFile/维新里。

实现一个简单的计数器,来限制软件的使用次数:
SetRegistryKey(_T("myboleApp"));
int x=GetProfileInt("test","times",0);
if(x>=5)
   return false;
WriteProfileInt("test","times",++x);
CString str;
str.Format("你还能使用%d次",5-x);
AfxMessageBox(str);

2. 读写WIN32注册表,做两个菜单进行注册表的读写操作,写的时候先打开所要操作键,也就是返回操作键的句柄用RegCreateKey(这个句柄包含主键和子键,第一个参数可以是一个已打开的句柄或者一个预定义的保留的句柄值,如果是前面这个已打开的句柄,那么可以根据这个已打开句柄和后面子键的参数,在这个已打开键的下面创建一个新的句柄),然后根据得到的这个句柄去读写。
在使用RegSetValue进行写操作的时候,写的类型必须是REG_SZ,这个类型可以理解成已’/0’结尾的字符串,如果我们想写别的数据类型,使用RegSetValueEx.
The RegSetValue function sets the data for the default or unnamed value of a specified registry key. The data must be a text string.
RegSetValue函数为默认的或没有名字的指定的注册表键设置数据,这个数据必须是字符串。
RegSetValue最后一个参数不包括’/0’
使用新函数在注册表任意位置读写:
写:
HKEY hKey;
RegCreateKey(HKEY_LOCAL_MACHINE,"software//收藏",&hKey);
//RegSetValue(hKey,NULL,REG_SZ,"WeiXin",6);
//RegSetValue(hKey,"课程",REG_SZ,"WeiXin",6);
DWORD i=100;//下面的参数要的是地址,所以这里要定义这个变量
RegSetValueEx(hKey,"JSP",NULL,REG_DWORD,(CONST BYTE*)&i,4);
RegCloseKey(hKey);
读:in bytes以字节为单位

读一个默认键的值:
char *buf;
long len;
RegQueryValue(HKEY_LOCAL_MACHINE,
"software//何问起网//mylyhu//abc",NULL,&len);
buf=new char[len];
RegQueryValue(HKEY_LOCAL_MACHINE,
"software//何问起网//mylyhu//abc",buf,&len);
MessageBox(buf);
delete [] buf;

RegQueryValue参数说明:
If lpValue is NULL, and lpcbValue is non-NULL, the function returns ERROR_SUCCESS, and stores the size of the data, in bytes, in the variable pointed to by lpcbValue. This lets an application determine the best way to allocate a buffer for the value\'s data. 
如果lpValue是NULL,并且lpcbValue不是NULL,这个函数返回ERROR_SUCCESS,并且通过lpcbValue所代表这个变量的指针存储数据的字节单位的的大小,这是让一个应用程序按照最好的方式去为查询值的数据分配空间

读一个有名字的键的值。
HKEY hKey;
RegCreateKey(HKEY_LOCAL_MACHINE,"software//维新",&hKey); 
DWORD dwType;
DWORD data;
DWORD len=4;
RegQueryValueEx(hKey,"JSP",NULL,&dwType,(BYTE*)&data,&len);
CString str;
str.Format("%d",data);
MessageBox(str);
::RegCloseKey(hKey);

锁注册表:
HKEY hKey;
RegCreateKey(HKEY_CURRENT_USER,"software//microsoft//windows//currentversion//policies//system",&hKey);
DWORD x=1;
RegSetValueEx(hKey,"DisableRegistryTools",0,REG_DWORD,(CONST BYTE*)&x,4);
RegCloseKey(hKey);

解注册表
HKEY hKey;
RegCreateKey(HKEY_CURRENT_USER,"software//microsoft//windows//currentversion//policies//system",&hKey);
DWORD x=0;
RegSetValueEx(hKey,"DisableRegistryTools",0,REG_DWORD,(CONST BYTE*)&x,4);
RegCloseKey(hKey);

推挤:http://www.cnblogs.com/roucheng/p/cppyiwei.html

以上是关于MFC文件操作的主要内容,如果未能解决你的问题,请参考以下文章

MFC常用操作

MFC文件操作

使用 Java 代码操作 MFC 对话框可执行文件

Windows核心编程——MFC下INI文件操作

Windows核心编程——MFC下INI文件操作

使用MFC操作EXCEL文件