在编程中运用CTypedPtrMap指针模板类的方法,其存储结构占用物理空间小,比单纯的用数组结构存储的文件将小很多,所以是一种非常推荐的存储及读取文件的方法。
你必须在stdafx.h文件中 包含 #include <afxtempl.h> // MFC templates在头文件中包含 #include <io.h>
其中 CBank.h文件如下:
class CBank : public CObject {DECLARE_SERIAL(CBank) //声明序列化存储public: CBank(); CBank(CString str){ m_bankname = str; } CBank(const CBank &b){ m_bankname= b.m_bankname;} //拷贝构造函数 virtual ~CBank();private: CString m_bankname;public: virtual void Serialize(CArchive& ar);};
typedef CTypedPtrMap<CMapStringToOb,
CString,
CBank*>CBanktmp; //这个才是我们根据此类生成的类型
它的实现文件.cpp如下:
IMPLEMENT_SERIAL(CBank, CObject, 1) //实现序列化存储CBank::CBank(){ m_bankname="";}CBank::~CBank(){
}void CBank::Serialize(CArchive& ar){ if (ar.IsLoading()) { ar >> m_bankname; } else { ar << m_bankname; }}
/*----------------------------------------------------从文件中读取参数:注意: 其中的m_map是这样定义的:CBanktmp m_map;-------------------------------------------------*/
void CDlgBankIn::LoadBankName(){ UINT nFlags = CFile::typeBinary |CFile::modeReadWrite; if(_access(_T("BankName.dat"),0)) { nFlags |= CFile::modeCreate; } CFile file; CFileException fe; if (file.Open(_T("BankName.dat"),nFlags, &fe)) { if(file.GetLength()==0) //如果文件为空则不进行读取操作 { } else { CArchive ar(&file, CArchive::load); m_map.Serialize(ar); //读取文件 //根据文件内容填充列表框 POSITION pos; CString strKey; CBank *pB=NULL; for( pos = m_map.GetStartPosition(); pos != NULL; ) { m_map.GetNextAssoc(pos,strKey,(CBank*)pB); m_CmbBank.AddString(strKey); } delete pB; } } file.Close();}
/*-------------------------------------------------功能: 先打开文件,然后查找文件中是否有与编辑框关键字相同的内容, 如果有相同内容则不添加,如果没有相同内容则写文件.------------------------------------- ------------*/
void CDlgBankList::OnBtnAdd() { // TODO: Add your control notification handler code here CString strKey; GetDlgItemText(IDC_EDITBank,strKey); if (0 != strKey.GetLength()) { CBank *pB; //打开文件 UINT nFlags = CFile::typeBinary |CFile::modeRead; CFile file; CFileException fe; if (file.Open(_T("BankName.dat"),nFlags, &fe)) { if(file.GetLength()==0) //如果文件为空则不进行序列化操作 {
} else { CArchive ar(&file, CArchive::load); m_map.Serialize(ar); } //分析文件并给文件添加编辑框的内容 if(!m_map.Lookup(strKey,(CBank*)pB)) //当不存在时才需要添加 { if (CB_ERR != m_ListBox.AddString(strKey)) { m_map.SetAt(strKey, new CBank(strKey)); //给关键字strKey赋值 } } } file.Close();
//存储文件 nFlags = CFile::typeBinary |CFile::modeWrite; if (file.Open(_T("BankName.dat"),nFlags, &fe)) { CArchive ar(&file, CArchive::store); m_map.Serialize(ar); //序列化存储 } }}
/*-------------------------------------------------功能: 先打开文件,然后查找文件中的关键字, 找到后则删除此关键字, 但是注意关键字对应的内容仍然没有删除,这点期待改进. -------------------------------------------------*/
void CDlgBankList::OnBtnDel() { // TODO: Add your control notification handler code here int iIndex; CString strKey; if(LB_ERR!=m_ListBox.GetCurSel()) { //打开文件 & nbsp; UINT nFlags = CFile::typeBinary |CFile::modeRead; CFile file; CFileException fe; if (file.Open(_T("BankName.dat"),nFlags, &fe)) { CArchive ar(&file, CArchive::load); m_map.Serialize(ar); iIndex=m_ListBox.GetCurSel(); m_ListBox.GetText(iIndex,strKey); m_ListBox.DeleteString(iIndex); //分析文件并给文件添加编辑框的内容 CBank *pB=NULL; if(m_map.Lookup(strKey,(CBank*)pB)) { m_map.RemoveKey(strKey); //删除关键字,但没有删除关键字对应的内容 } } file.Close(); //存储文件 nFlags = CFile::typeBinary |CFile::modeWrite; if (file.Open(_T("BankName.dat"),nFlags, &fe)) { CArchive ar(&file, CArchive::store); m_map.Serialize(ar); //序列化存储 } }} ============CArchive类是使用了缓冲区,即一段内存空间作为临时数据存储地,对CArchive的读写都先依次排列到此缓冲区,当缓冲区满或用户要求时,将此段整理后的数据读写到指定的存储煤质。
一般来说,CArchive封装了对该缓冲区的操作,它的好处是可以少划动硬盘以及提高运行速度。不过对于使用MFC来说,是一个很好的封装。看看其对读写的操作,可见在实际编程上是非常容易出错的。对于这样的类,一定要封装好,作为一个公用函数或公用类调用,否则在实际中像c那样散在代码的各个地方的话,恐怕有时头会大。
有时我想,如果编程在这些地方磨洋工的话,恐怕一个大的工程软件写起来得好长时间。所以说尽量已组件的方式,类的思路来组合前人的算法,技巧也是一种编程的进步。
所下列看其对指针的娴熟操作(也是往往出错的啊),
例如双字的插入(写)
CArchive& CArchive::operator<<(DWORD dw) { if (m_lpBufCur + sizeof(DWORD) > m_lpBufMax) //缓冲区空间不够 Flush(); //缓冲区内容提交到实际存储煤质。 if (!(m_nMode & bNoByteSwap)) _AfxByteSwap(dw, m_lpBufCur); //处理字节顺序 else *(DWORD*)m_lpBufCur = dw; //添入缓冲区 m_lpBufCur += sizeof(DWORD); //移动当前指针 return *this; }双字的提取(读)
CArchive& CArchive::operator>>(DWORD& dw) { if (m_lpBufCur + sizeof(DWORD) > m_lpBufMax) //缓冲区要读完了 FillBuffer(sizeof(DWORD) - (UINT)(m_lpBufMax - m_lpBufCur)); //重新读入内容到缓冲区 dw = *(DWORD*)m_lpBufCur; //读取双字 m_lpBufCur += sizeof(DWORD); //移动当前位置指针 if (!(m_nMode & bNoByteSwap)) _AfxByteSwap(dw, (BYTE*)&dw); //处理字节顺序 return *this; }