&&&&&&&上一节中鸡啄米讲了定时器timer的用法,本节介绍下文件操作类cfile类的使用。
&&&&&& cfile类概述
&&&&&&&如果你学过c语言,应该知道文件操作使用的是文件指针,通过文件指针实现对它指向的文件的各种操作。这些文件操作函数中有的最终还是调用了操作系统的api函数或者处理过程与之类似,例如在windows系统中,fread函数就调用了api函数readfile。
&&&&&&&windows系统的api函数除了readfile,还有createfile、writefile等函数。而mfc基于面向对象的思想,将这些windows api函数封装到了cfile类中,实现对文件的打开、关闭、读、写、获取文件信息等操作。使用cfile类对文件进行操作非常便捷。
&&&&&& cfile类的成员函数
&&&&&& cfile( );
&&&&&& cfile(handle hfile);
&&&&&& cfile(lpctstr lpszfilename,uint nopenflags);
&&&&&& 以上三个成员函数都是cfile的构造函数,用于构造cfile对象。参数hfile为要关联到cfile对象的文件的句柄。参数lpszfilename为要关联到cfile对象的文件的相对路径或者绝对路径;参数nopenflags为文件访问选项的组合,通过各选项的按位或运算实现组合,下面的5个表列出了nopenflags参数可能取的选项:
&&&&&& 下面的文件访问模式选项表中只能选择一个进行组合,默认取cfile::moderead。
取值 | 描述 |
cfile::moderead | 只读方式访问文件 |
cfile::modewrite | 写入方式访问文件 |
cfile::modereadwrite | 读写方式访问文件 |
&&&&&& 下面的文件共享模式选项表中也只能选择一个进行组合,默认的共享模式是cfile::shareexclusive。
取值 | 描述 |
cfile::sharedenynone | 允许其他进程对文件进行读写 |
cfile::sharedenyread | 不允许其他进程读取文件 |
cfile::sharedenywrite | 不允许其他进程写文件 |
cfile::shareexclusive | 禁止其他进程对文件的所有访问 |
&&&&&&&下面的文件创建模式选项列表中可选择第一个或两者都选进行组合。
取值 | 描述 |
cfile::modecreate | 如果文件不存在则创建文件,而如果存在则将它关联到此cfile对象并将长度截取为0 |
cfile::modenotruncate | 如果文件不存在则创建文件,而如果存在则将它关联到此cfile对象而不进行截取 |
&&&&&& 注意,选择cfile::modenotruncate时需要与cfile::modecreate一起使用,即cfile::modecreate | cfile::modenotruncate。
&&&&&& 另外,还有一个文件缓冲选项列表和一个文件安全选项。文件缓冲选项不太常用,鸡啄米这里就不讲了,有兴趣的可以查阅msdn。文件安全选项是cfile::modenoinherit,意为禁止子进程继承使用此文件。
&&&&&& 当然,在实际使用时,以上各个表并不是都要用到,大家可以根据自己的需要选择用哪个表,选择哪个选项。
&&&&&& virtual bool open(lpctstr lpszfilename,uint nopenflags,cfileexception* perror = null);
&&&&&& 打开文件。它通常与默认构造函数cfile::cfile()一起使用。参数lpszfilename和nopenflags同构造函数。参数perror为指向文件异常对象的指针,默认为null。
&&&&&& virtual void close( );
&&&&&& 关闭文件。如果你没有在执行析构函数前调用此成员函数关闭文件,则析构函数会为你关闭。
&&&&&& virtual uint read(void* lpbuf,uint ncount);
&&&&&&&读取文件数据到缓存。参数lpbuf是由用户提供的指向接收文件数据的缓存的指针;参数ncount为读取的最大字节数。返回值是实际读取到缓存的字节数,如果到达文件尾则返回值可能会小于ncount,此时继续读取的话,会返回0,所以通常我们都会判断返回值是否小于ncount或者等于0来确定是否到达文件尾。
&&&&&& virtual void write(const void* lpbuf,uint ncount);
&&&&&& 将缓存中的数据写入文件。参数lpbuf也是由用户提供,指向包含写入数据的缓存的指针;参数ncount为缓存中要被写入文件的数据的字节数。
&&&&&& virtual ulonglong seek(longlong loff,uint nfrom);
&&&&&& 在一个打开的文件中重定位文件指针。参数loff为文件指针移动的字节个数,为正数时表示向文件尾移动,为负数时表示向文件开头移动;参数nfrom为loff的基准位置,即由nfrom位置开始移动loff个字节,它可以取下面几个值中的一个:
&&&&&& cfile::begin&&&&&& 从文件开头开始移动
&&&&&& cfile::current&&& 从文件指针的当前位置开始移动&
&&&&&&&cfile::end&&&&&&&&& 从文件尾开始移动
&&&&&& 文件打开时,文件指针被置于0,即文件开头处。
&&&&&& 如果此函数成功则返回文件指针的位置。
&&&&&& void seektobegin( );
&&&&&& 将文件指针移动到文件开头。它等价于seek( 0l, cfile::begin )。
&&&&&& ulonglong seektoend( );
&&&&&& 将文件指针移动到文件末尾。返回值是文件的字节长度。它等价于cfile::seek( 0l, cfile::end )。
&&&&&& virtual ulonglong getlength( ) const;
&&&&&& 获取文件的字节长度。
&&&&&& virtual void setlength(ulonglong dwnewlen);
&&&&&& 改变文件的长度。参数dwnewlen为文件的新长度,它可能比文件的当前长度值要大或者小,文件会相应的被扩展或截取。
&&&&&& virtual cstring getfilename( ) const;
&&&&&& 获取文件名称。
&&&&&& virtual cstring getfilepath( ) const;
&&&&&& 获取文件的绝对路径。
&&&&&& virtual cstring getfiletitle( ) const;
&&&&&& 获取文件的显示名称。举个例子,与getfilename区分一下,如果你系统中的文件不显示扩展名,则它获取到的文件名称就不包含扩展名,否则就显示扩展名。
&&&&&& virtual ulonglong getposition( ) const;
&&&&&&&获取文件指针的当前位置。
&&&&&& static void pascal remove(lpctstr lpszfilename,catltransactionmanager* ptm = null);
&&&&&& 删除文件。参数lpszfilename为要删除的文件路径,可以是相对路径、绝对路径或者网络路径;参数ptm指向一个catltransactionmanager对象。
&&&&&& static void pascal rename(lpctstr lpszoldname,lpctstr lpsznewname,catltransactionmanager* ptm = null);
&&&&&& 重命名文件。参数lpszoldname为老的文件路径;参数lpsznewname为新的文件路径;参数ptm指向一个catltransactionmanager对象。实际上此函数的意义已经不只是重命名文件,还可以移动文件到其他目录下,例如,lpszoldname取"d:\\1.txt",lpsznewname取"e:\\2.txt",这样可以将d盘中的1.txt文件转移到e盘并重命名为2.txt。
&&&&&& cfile类应用实例
&&&&&& 这里鸡啄米只给大家演示几个简单的代码片段,从这些代码片段中熟悉cfile类的文件操作。
&&&&&& 实例一:构造cfile对象时就打开文件,然后向文件中写入数据,最后以seek函数移动文件指针,读取文件内容。
- char&writebuffer[500];&&&&&//&要写入的数据的缓存 &&
- char&readbuffer[500];&&&&&&//&存放读取数据的缓存 &&
- longlong&loff&=&0;&&&&&&&&&//&文件指针的偏移量,也是读取到的数据的总字节数&&
- //&构造cfile对象,同时以创建和读写的方式打开文件e:\1.txt &&
- cfile&file(_t("e:\\1.txt"),&cfile::modecreate&|&cfile::modereadwrite); &&
- &&
- //&将写入数据的缓存中每个字节都赋值为字符c &&
- memset(writebuffer,&'c',&sizeof(writebuffer)); &&
- //&将数据写入到文件中 &&
- file.write(writebuffer,&sizeof(writebuffer)); &&
- &&
- while&(true) &&
- { &&
- &&&&//&以文件开头为基准,移动文件指针到loff的位置 &&
- &&&&file.seek(loff,&cfile::begin); &&
- &&&&//&读取100个字节的数据到存放读取数据的缓存的readbuffer&+&loff位置处 &&
- &&&&int&nret&=&file.read(readbuffer&+&loff,&100); &&
- &&&&//&根据实际读取的字节数,增加文件指针的移动量 &&
- &&&&loff&+=&nret; &&
- &&&&//&如果读取数据时返回值小于指定的100,说明已到文件尾,跳出循环 &&
- &&&&if&(nret&<&100) &&
- &&&&&&&&break; &&
- } &&
- &&
- //&关闭文件 &&
- file.close();&&
&&&&&& 实际上,在write函数和read函数执行后,文件指针会自动移动到最后操作的位置,所以其实上面的代码中无须使用seek函数再去手动移动文件指针。这将在下面的实例二中体现出来。
&&&&&& 实例二:构造cfile对象,然后使用open成员函数打开文件,再写入一个结构体数组,最后读取出来。
&&&&&& 先贴上结构体的定义:
- struct&student &&
- { &&
- &&&&int&&nnum; &&&&
- &&&&float&fscore; &&
- };&&
&&&&&&&下面是文件操作的代码片段:
- student&s1[2];&&&//&存放要写入文件的数据 &&
- student&s2[2];&&&//&存放从文件读取的数据 &&
- cfile&file;&&&&&&//&cfile对象 &&
- int&nreadbytes&=&0;&&&//&从文件中读取到的总字节数 &&
- &&
- //&为s1数组各元素赋值 &&
- s1[0].nnum&=&22; &&
- s1[0].fscore&=&91.5; &&
- s1[1].nnum&=&23; &&
- s1[1].fscore&=&85; &&
- &&
- //&以创建、读写方式打开文件e:\1.txt &&
- if&(file.open(_t("e:\\1.txt"),&cfile::modecreate&|&cfile::modereadwrite)) &&
- { &&
- &&&&//&写入数据s1结构体数组 &&
- &&&&file.write(s1,&sizeof(s1)); &&
- &&&&//&因为上面调用write以后文件指针在文件尾,所以需要将其移动到文件开头 &&
- &&&&file.seektobegin(); &&
- &&
- &&&&while&(true) &&
- &&&&{ &&
- &&&&&&&&//&读取数据到s2 &&
- &&&&&&&&int&nret&=&file.read((byte*)s2&+&nreadbytes,&sizeof(student)); &&
- &&&&&&&&//&计算已经读取到的总字节数 &&
- &&&&&&&&nreadbytes&+=&nret; &&
- &&&&&&&&//&如果读取数据时返回值小于指定的sizeof(student),则说明已到文件尾,跳出循环 &&
- &&&&&&&&if&(nret&<&sizeof(student)) &&
- &&&&&&&&&&&&break; &&
- &&&&} &&
- &&
- &&&&//&关闭文件 &&
- &&&&file.close(); &&
- }&&
&&&&&& 本节内容就到这里,如果有其他语言的文件操作的经验的话,应该还是比较简单的。鸡啄米很高兴能在大家的编程入门之路上贡献自己一点微薄的力量。