Cmap和Carray以及Cstring的使⽤以及MFC中的⽂件读写CMap的使⽤
为什么使⽤CMap:
如果你要存储的每个数据⾄少有⼀个唯⼀的标志(数字、字符、字符串、类的对象。。。),并且这些数据会频繁的被查和替换。那么你就需要使⽤CMap类来简化你的代码,提⾼你的效率。
CMap就是对Hash表的⼀种实现。对于Hash表来说,我们需要提供成对的Key与Value进⾏操作,其实,也就是将我们⽇常使⽤的数组下标替换成现在Key,这样就⽅便我们使⽤key来查到相应的Value,提⾼我们遍历的速度。⾄于MFC是采⽤了什么样的散列函数,我们不必知道。
头⽂件: afxtempl.h
CMap的格式:
template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE >class CMap : public CObject
Key:⽤作Key的类型(⽐如整型、浮点型等) ARG_KEY:Key的值 VALUE: ⽤作VALUE的类型 ARG_VALUE:⽤作VALUE的值
1. 要使⽤Cmap,那么⾸先我们要实例化⼀个CMap的类型 举例:
typedef CMap<int, int, CString, CString> CMapPnt; //⽐如学⽣名册的列表 typedef CMao<CPoin, CPoin,CTime, CTime> CMapTime;//⽐如不同经纬度的时间 typedef CMap<CMyType, CMyType, CThing, CThing> CMyThing; //⽐如⾃⼰的私有物品的列表
任何类型都可以⽤作key或者value的类型。但是正如我们前⾯所说,key是⼀个唯⼀的标志,⽤以加快我们的查询速度。
2.我们举例来说明CMap的查询、遍历、删除等⽤法。
⽐如⼀个班级的花名册,那么学⽣的学号是唯⼀的,所以我们有了下⾯这个CMap的实例。 在使⽤之前声明:
typedef CMap<int, int, CString, CString> CMapStu;
使⽤时,我们认为CMapStu是⼀个类型就可以了。 CMapStu m_class1; //班级1
3.添加:void SetAt(ARG_KEY key, ARG_VALUE newValue); 此函数会以Key值遍历列表,当查到key值后使⽤newValue替换以前的Value值。如果没有到key值,则添加此项。
m_class1.SetAt(001, "张三"); m_class1.SetAt(002, "张A"); m_class1.SetAt(003, "张B"); m_class1.SetAt(004, "张C");
4.查:Lookup(ARG_KEY key, ARG_VALUE& newValue)如果到Key值,则newValue等于其存储的Value值,返回值为⾮0。 如果未到,则返回值为0.
int studentId = 1; CString studentName;
if (m_class1.Lookup(studentId, studentName)) {
AfxMessageBox("ID号: %d, 姓名: %s", studentId, studentName); }
5.遍历:CMap提供了专门⽤作遍历的类型CPair,CPair顾名思义,就是⼀对。其中包含⼀个Key和对应的Value。
CMapStu::CPair* pCurValue= m_class1.PGetFirstAssoc(); while(pCurVal != NULL) {
CString str;
str.Format("学号: %d, 姓名:%s", pValue->key, pValue->value);
pCurValue = m_class1.PGetNextAssoc(); }
6.删除⼀个元素:RemoveKey(ARG_KEY key)
如果当前Key值存在,则返回⾮0值,如果不存在,则返回0值。 int studentId = 1;
RemoveKey(1); //删除学号为1的学⽣信息
7.删除所有元素:RemoveALL()
CMap<int,int,CPoint,CPoint> myMap;
// Add 10 elements to the map. for (int i=0;i < 10;i++)
myMap.SetAt( i, CPoint(i, i) );
myMap.RemoveAll();
CArray使⽤
我们在使⽤vc进⾏⽐较复杂的编程时,经常需要⽤到复杂的数组结构,并希望能实现动态管理。由于C++并不⽀持动态数组,MFC提供了⼀个CArray类来实现动态数组的功能。有效的使⽤CArray类,可以提⾼程序的效率。
MFC提供了⼀套模板库,来实现⼀些⽐较常见的数据结构如Array,List,Map。CArray即为其中的⼀个,
⽤来实现动态数组的功能。 CArray是从CObject派⽣,有两个模板参数,第⼀个参数就是CArray类数组元素的变量类型,后⼀个是函数调⽤时的参数类型。
我们有⼀个类 class Object,我们要定义⼀个Object的动态数组,那么我们可以⽤以下两种⽅法:
CArray<Object,Object> Var1;
CArray<Object,Object&> Var2;
Var1与Var2哪⼀个的效率要⾼呢? Var2的效率要⾼。为什么呢?
CArray下标访问是⾮安全的,它并没有超标预警功能。虽然使⽤ASSERT提⽰,但下标超范围时没有进⾏处理,会引起⾮法内存访问的错误。
前⾯谈到模板实例化时有两个参数,后⼀个参数⼀般⽤引⽤,为什么呢?看看Add成员函数就可以明。Add函数的作⽤是向数组添加⼀个元素。下⾯是它的定义: int CArray<TYPE, ARG_TYPE>::Add(ARG_TYPE newElement)
Add函数使⽤的参数是模板参数的⼆个参数,也就是说,这个参数的类型是我们来决定的,可以使⽤Object或Object&的⽅式。熟悉
C++的朋友都知道,传引⽤的效率要⾼⼀些。如果是传值的话,会在堆栈中再产⽣⼀个新的对象,需要花费更多的时间。
Cstring的使⽤
CString类的⼏种基本操作:
1、长度:GetLength();
CString str(_T("abc")); int len = str.GetLength(); //len == 3
2、是否为空(即不含字符):IsEmpty();
3、清空字符串:Empty();
CString str(_T("abc"));
BOOL mEmpty = str.IsEmpty(); //mEmpty == FALSE str.Empty();
mEmpty = str.IsEmpty(); //mEmpty == TRUE
4、转换⼤⼩写:MakeUpper(),MakeLower();
5、转换顺序:MakeReverse();
⼆、字符串的查
1、Find:从制定位置开始查指定字符串,返回其位置(不到返回-1) CString str(_T("abcdefg"));
int idx = str.Find(_T("cde"), 0); //idx 的值为2;
2、ReverseFind:从字符串末尾开始查指定的字符,返回其位置,不到返回 -1,虽然是从后向前查,但是位置为从开始算起;CString str(_T("abcdefg"));
int idx = str.ReverseFind('e'); //idx 的值为4;
3、FindOneOf:查参数中给定字符串中的任意字符,返回第⼀次出现的位置 CString str(_T("abcabcd"));
int idx = str.FindOneOf(_T("cbd")); //idx 的值为1;
三、字符串的提取
Left,Mid,Right:分别实现从CString对象的左、中、右进⾏字符串的提取操作 CString str(_T("abcd")
);
CString strResult = str.Left(2); //strResult == ab
strResult = str.Mid(1); //strResult == bcd
strResult = str.Mid(0, 2); //strResult == ab
strResult = str.Right(2); //strResult == cd
⽂本⽂件的读写
MFC主要读写⽂件的类是CFile,⽽CStdioFile类是派⽣⾃CFile类的,主要增加了⼀个按⾏的⽅式读取/写⼊⽂件每⾏字符串的功能!别的地⽅没咋研究!
//CFile读取所有⽂件到缓冲区:
CFile file;
char buffer[1024];
if(!file.Open("c://",CFile::modeRead))return; //打开aaa这个⽂件,打开形式为读取
file.Read(buffer,1024); //将⽂件的内容从开始,读1024到缓冲区(如果想读取不同地⽅的数据
则需要设置游标函数Seek,SeekToBegin,SeekToEnd..)
file.Close();
//CFile写内容到⽂件
CFile file;
char buffer[1024] = "在此添加要写⼊⽂件的字符串!";
if(!file.Open("c://",CFile::Create | CFile::Write))return; //打开aaa这个⽂件,打开形式为
(⽆此⽂件则新建)写⼊
file.Write(buffer,strlen(buffer));
file.Close();
//CStdioFile类的例⼦:
CStdioFile file;
CString str; //StdioFile可以直接使⽤字符串类CString的类型
if(!file.Open("c://",CFile::modeRead))return; //打开aaa这个⽂件,打开形式为读取
file.ReadString(str); //读⼀⾏内容到str字符串,注意此时⽂件的游标将⾃动设置到下⼀⾏的开头位置,所以如果想读下⼀⾏还是⽤
file.ReadString(str);
file.Close();
正确的⽂本⽂件读写过程
1.定义⽂件变量;
2.打开指定的⽂件;
3.向从⽂本⽂件中写⼊信息;
4.从⽂本⽂件中读取信息;
5.关闭⽂件
1、定义⽂件变量
定义⽂件变量格式:CStdioFile ⽂件变量;
例如,定义⼀个名称为f1的⽂件变量,语句如下:CStdioFile f1;
2,打开指定⽂件
可以直接通过CStdioFile的构造函数来打开磁盘⽂件,同时可以⽤标志位指定打开⽅式(只读、只写、读写等):
CStdioFile(LPCTSTR lpszFileName,UINT nOpenFlags);
其中,lpszFileName表⽰要打开的⽂件名,可以是相对路径或绝对路径
nOpenFlags设置⽂件打开⽅式标志位,可以指定⽤“|”连接多个标志位。
下⾯是常⽤的打开标志:
CFile::modeRead:以只读⽅式打开⽂件
CFile::modeReadWrite:以可读可写⽅式打开⽂件
CFile::modeWrite:以只写⽅式打开⽂件
此外,可以不在构造函数中打开⽂件,⽽仅仅调⽤空的构造函数CStidoFile(),然后⽤CStdioFile::Open()打开⽂件。Open函数的前两个参数和⾮空构造函数的参数相同,其声明如下:
BOOL Open(LPCTSTR lpszFileName,UINT nOpenFlags,CFileException* pError=NULL); 第3个参数与打开失败时的异常处理有关。
实例1:以只读⽅式打开⼀个⽂件
char * pszFileName="C:\\"; CStdioFile myFile;
CFileException fileException;
if(!myFile.Open(pszFileName,CFile::modeCreate|CFile::typeText|CFile::modeRead),&fileException) {
TRACE("Can't open file %s, error = %u\n",pszFileName,fileException.m_cause); }
运⾏结果:如果C:\下没有⽂件,则新⽣成该⽂件。
3.向从⽂本⽂件中写⼊信息
CStdioFile提供了函数WriteString来向⽂本⽂件中写⼊⽂本,WriteString函数的格式如下: void WriteString(LPCTSTR lpsz); WriteString的参数lpsz是⼀个以”\0”字符结束的字符串,要把这个字符串的内容写⼊⽂件。
提⽰:使⽤WriteString函数时,如果希望每执⾏⼀次WriteString,⽂本⽂件中的内容就会⾃动换⾏⼀次,那么就需要在需要换⾏的地⽅输出“\n”: myFile.WriteString(“第1⾏\n”);
实例2:向⽂件中写⼊⽂本
建⽴MFC基于对话框的程序,删除⾃动添加的所有控件,添加⼀个“确定”按钮,双击按钮,按默认添加事件函数,双击按钮,在相应的函数处添加如下代码: char* pszFileName="C:\\"; CStdioFile myFile;
CFileException fileException;
if(myFile.Open(pszFileName,CFile::typeText|CFile::modeCreate|CFile::modeReadWrite),&fileException) {
myFile.WriteString("第1⾏\n");
CString strOrder;
strOrder.Format("%d,%.3f",66,88.88);
myFile.WriteString(strOrder);
}
else {
TRACE("Can't open file %s,error=%u\n",pszFileName,fileException.m_cause); }
程序运⾏结果:C:\⽂件中内容如下:
第1⾏
66,88.880
4.从⽂本⽂件中读取信息
CStidoFile提供了函数ReadString来读取⽂本,ReadString有两种形式,⼀种为:
write的返回值
virtual LPTSTR ReadString(LPTSTR lpsz, UINIT nMax);
ReadString函数的参数如下:
lpsz :是⽤户提供的⼀个指向字符串的指针,它⽤来接受从⽂件读出的⽂本,以”\0”结束。
nMax是本次所允许读⼊的⽂本字符个数,不计“\0”字符,也就是说最多能读⼊nMax-1个⽂本字符。
ReadString的返回值是⼀个LPTSTR类型的指针,它指向从⽂件读出的⽂本字符串,如果到达⽂件尾,则返回NULL。
ReadString的另⼀种形式为:
BOOL ReadString(CString& rString);
参数rString⽤来容纳从⽂件读出的⽂本。
CString版本忽略回车换⾏符,返回值是⼀个布尔值。如果返回值为FALSE,表⽰因到达⽂件尾⽽没有读到任何字符。
提⽰:每执⾏⼀次ReadString,就会⾃动从⽂本⽂件中读取⼀⾏数据,同时⽂件操作指针会⾃动跳转
到下⼀⾏。
实例3:从⽂件中读取⽂本信息
char* pszFileName="C:\\";
CStdioFile myFile;
CFileException fileException;
if(myFile.Open(pszFileName,CFile::typeText|CFile::modeReadWrite),&fileException) { myFile.SeekToBegin();
CString str1;
myFile.ReadString(str1);
CString str2;
myFile.ReadString(str2);
AfxMessageBox(str1+str2);
}
else
{
TRACE("Can't open file %s,error=%u\n",pszFileName,fileException.m_cause);
}
myFile.Close();
5.关闭⽂件
对⽂件的操作完成后,使⽤CloseFile关闭⽂件。
函数CStdioFile::Close关闭⼀个⽂件,⼀般⼀个⽂件使⽤完毕就应该关闭它:
myFile.Close();
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论