C++对于文件的操作的方式有很多种,大体分为4类。第一类是c函数,第二类是运用c++的fstream类对文件进行操作,第三类是运用Windows API函数进行文件操作,第四类是运用MFC的类CFile对文件进行操作。
今天主要是想说一下运用CArchive,CFile类进行文件的操作。个人觉得这种方法比较简便常用,但有利必有弊,相对于c函数和c++的fstream,似乎灵活性要差一些,而且需要依赖于MFC类库。
CArchive允许以一个永久二进制(通常为磁盘存储)的形式保存一个对象的复杂网络,它可以在对象被删除时,还能永久保存。可以从永久存储中装载对象,在内存中重新构造它们。使得数据永久保留的过程就叫作“串行化”。
代码:
对于文件的写操作:分别写入一个int,char,float,CString类型的数据到”1.txt”文件中。
void CFileOperate::FileWrite()
{
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("http:://www.flyhorse.cn");
//保存数据
ar<<I<<CH<<F<<STR; 运用<<直接向文件中写入数据
ar.Close();
file.Close();
AfxMessageBox("数据保存成功!");
}
对于文件的读操作:从”1.txt”文件中读出上边写的int,char,float,CString类型的数据。
void CFileOperate::FileRead()
{
CFile file("1.txt",CFile::modeRead);
CArchive ar(&file,CArchive::load);
int i;
char ch;
float f;
CString str;
CString strResult;
//读取数据
ar>>i>>ch>>f>>str; //这里需要注意的是读出数据的顺序要跟写入数据的顺序相同
ar.Close();
file.Close();
strResult.Format("%d,%c,%f,%s",i,ch,f,str);
AfxMessageBox(strResult);
}
是不是很方便,可以对任意类型的数据随意的读写,而且数据都是以二进制的形式存储到文件中的,可以用UE打开1.txt查看文件的二进制格式。
而运用CFile和CArchive更多的是对象的串行化,将类的对象以二进制的形式串行化到文件中,使得类的对象得以永久保存。
但是想方便的进行对象的存储,总是需要点条件的,那就是这个对象必须是支持串行化的,也就是说不是所有的对象都可以用CArchive串行化到文件中,是不是很受打击?就好像想给人一块美味可口的蛋糕,但是前提你得先围着操场跑几圈一样.幸运的是创建一个支持串行化的类并不复杂,只要按照以下5步进行创建,就大功告成啦!
1. 从CObject派生类或者是从CObject派生的某个类派生。
2. 重写Serialize成员函数。
3. 使用DECLARE_SERIAL宏(在类中声明)。该宏形式如下:
DECLARE_SERIAL(class_name) //class_name串行化类的类名
4. 定义一个不带参数的构造函数。
5. 在类的实现文件中使用IMPLEMENT_SERIAL宏。该宏形式如下:
IMPLEMENT_SERIAL(class_name,base_class_name, wSchema) // wSchema版本号
通过上边5个步骤就可以创建一个支持串行化的类了。
例如我想创建一个存储用户信息的支持串行化的CUserInf类,代码如下:
###############CUserInf.h##################################
class CUserInf:public CObject
{
DECLARE_SERIAL(CUserInf) // DECLARE_SERIAL宏
public:
CUserInf(); //不带参数的构造函数
CUserInf(CString username,CString passwd,CString question,CString answer);
virtual ~CUserInf();
void Serialize(CArchive& ar); //重写Serialize函数
void GetUserInf(CString &userinf);
private:
CString _username; //用户名
CString _passwd; //密码
CString _question; //密保问题
CString _answer; //答案
};
############################CUserInf.cpp#########################
IMPLEMENT_SERIAL(CUserInf,CObject,1) // IMPLEMENT_SERIAL宏
CUserInf::CUserInf() //不带参数的构造函数
{
}
CUserInf::CUserInf(CString username,CString passwd,CString question,CString answer)
{
_username=username;
_passwd=passwd;
_question=question;
_answer=answer;
}
CUserInf::~CUserInf()
{
}
void CUserInf::Serialize(CArchive& ar) //重写的Serialize函数
{
if(ar.IsStoring()) //向文件中存储对象
{
ar< _username< _passwd< _question< _answer;
}
Else //从文件中取出对象
{
ar>>this->_username>>this->_passwd>>this->_question>>this->_answer;
}
}
void CUserInf::GetUserInf(CString &userinf)
{
userinf=_username+" "+_passwd+" "+_question+" "+_answer;
}
以上就是一个支持串行化的类的创建,只需5步,就大功告成!
下边我们来看看如何将我们的类串行化到文件中。
向文件中写入对象:
void CCArchivetestDlg::UserInfWrite()
{
// 创建两个对象
CUserInf user1("悟空","123","我的名字?","孙行者");
CUserInf user2("八戒","456","我的名字?","猪悟能");
//创建或打开userinf.archive文件,进行写操作
CFile file("userinf.archive",CFile::modeCreate|CFile::modeWrite);
CArchive iar(&file,CArchive::store);
//向文件中写入对象
iar<<&user1<<&user2;
//ar.WriteObject(&user1);
//ar.WriteObject(&user2);
iar.Close();
file.Close();
MessageBox("用户信息写入成功!");
}
从文件中读取对象:
void CCArchivetestDlg::UserInfRead()
{
//定义两个对象指针
CUserInf *puser1=NULL;
CUserInf *puser2=NULL;
CFile file("userinf.archive",CFile::modeRead);
CArchive oar(&file,CArchive::load);
//从文件读取数据
oar>>puser1>>puser2;
oar.Close();
file.Close();
CString user1;
CString user2;
puser1->GetUserInf(user1);
puser2->GetUserInf(user2);
MessageBox(user1+user2);
}
以上为对象的串行化和反串行化过程,希望对读者有帮助!