关于文件异常捕获--新手篇

来源:互联网 发布:重庆大学网络自助 编辑:程序博客网 时间:2024/06/05 01:50
 文件输入和输出服务是所有操作系统的主要工作,不必惊奇,MicroSoft Windows提供了各种API函数用来读、写和操作磁盘文件。MFC将这些函数封装在CFile类里,CFile允许把“文件”当做对象,并用CFile的成员函数(如:read、write等)对文件进行操作。CFile具有MFC编程人员实现低级文件IO所需要的所有操作。

      编写文件IO最主要的是为了支持文档的存储和加载,尽管用CFile对象实现磁盘文档的读写没有什么困难,但大部分MFC应用程序不会这么做,而是用CArchive对象。

1CFile类

      CFile是比较简单的类,它封装了Win32用来处理文件IO的那部分。在多于25个的成员函数中有用来打开和关闭文件的函数、读写文件数据的函数、删除和重命名文件的函数、检索文件信息的函数。它的public成员数据之一m_hFile保存了与CFile对象相关联的文件的句柄、protected成员m_strFileName保存着文件的名称。成员函数GetFilePath、GetFileName、GetFileTitle可以用来提取整个文件名或文件名的一部分。例如:如果完整的文件名和路径名为C:/personal/File.txt,那么GetFilePath返回整个字符串,GetFileName返回File.txt,GetFileTitle返回File。

      但是如果细讲这些函数,就等于忽略了对编程人员来说CFile拥有的重要功能,即用来读写磁盘文件的函数。下面的几部分简要介绍了CFile的使用方法,以及错误发生时CFile的通知方式(如果从来没有用过C++异常处理,现在开始吧)。

1.1打开关闭和创建文件

      用CFile打开文件有2中方法,第一种方法是构造一个没有初始化的CFile对象并调用CFile::Open。下面的代码段就用了这个方法打开一个具有读写访问权的文件File.txt。因为函数的第一个参数没有给出路径名,如果该文件不在当前目录下,Open就会失败。

CFile file;

if(file.Open("File.txt",CFile::modeReadWrite))

{

      //It Worked

}

CFile::Open返回一个BOOL值,表示是否成功打开文件。返回非零值意味着文件打开了,零意味着文件没有打开。如果CFile::Open返回零,并且你想知道调用失败的原因,则创建一个CFileException对象并把它的地址传送到Open函数的第三个参数中。

[cpp] view plaincopyprint?
  1. CFile file;  
  2. CFileException e;  
  3. if(file.Open("File.txt",CFile::modeReadWrite,&e))  
  4. {  
  5.       //It Worked   
  6. }  
  7. else  
  8. {  
  9.       e.ReportError();//Open failed.Tell the user why.  
  10. }  
 

如果Open失败,则它用“描述失败本质的信息”将CFileException对象初始化。ReportError在该信息的基础上显示一条错误信息通过检查CFileException的公用数据成员m_cause,你可以找出导致失败的原因。详细信息见msdn

      第二种方法是用CFile的构造函数打开文件。不必构造一个空的CFile对象并调用Open,可以这样创建一个CFile对象,并用一个语句打开文件:CFile file("File.txt",CFile::modeReadWrite);如果文件不能打开,CFile的构造函数会引发一个CFileException。因此,利用CFile的构造函数打开文件通常使用try和catch块来俘获错误。

[cpp] view plaincopyprint?
  1. try  
  2. {  
  3.       CFile file("File.txt",CFile::modeReadWrite);  
  4.       //......   
  5. }  
  6. catch(CFileException* e)  
  7. {  
  8.       e->ReportError();  
  9.       e->Delete();  
  10. }  
 

是否删除MFC发送给你的CFileException对象,决定权在你。这就是在处理异常后该示例调用Delete删除异常对象的原因。不想调用Delete的唯一场合就是你要用throw重新发送异常,但这种情况很少见。

      如果要创建一个新文件而不是打开一个现存文件,则要在CFile::Open或CFile::CFile函数的第二个参数中包含一个CFile::modeCreate标志。CFile file("File.txt",CFile::modeReadWrite | CFile::modeCreate);如果用这种方法创建的文件已经存在,则清空它的内容。

      如果要创建一个不存在的文件 或 要在文件存在但没有被截去时打开该文件,则要包含一个CFile::modeNoTruncate标志:CFile file("File.txt",CFile::modeReadWrite | CFile::modeCreate | CFile::modeNoTruncate);按这种方式打开文件基本上总是成功的,因为如果该文件不存在,他能自动生成。

      在默认方式下,CFile::Open或CFile::CFile函数打开文件时会获得该文件的独占访问权,也就是说其他人不能再打开该文件。如果有必要,在打开文件时可以指定共享模式,明确的允许其他人访问该文件,如下的几种共享模式

CFile::shareDenyNone没有读写访问限制、CFile::shareDenyRead禁止读访问权、CFile::shareDenyWrite禁止写访问权、CFile::shareExclusive禁止读写访问权(默认值)。还要3种读写访问权CFile::modeReadWrite请求读写访问权、CFile::modeRead请求读访问权、CFile::modeWrite请求写访问权。这些选项的常见用法是允许任一客户读取文件,但禁止往文件上写。

      关闭打开的文件有2种方式。如果要显式关闭文件,则对应的CFile对象调用Close函数。如果你喜欢,可以用CFile的析构函数关闭文件。如果文件还没有关闭,类的析构函数则调用Close。这就是说,在堆上创建的CFile对象在失效后会自动关闭。有时程序员显示调用Close的原因是:关闭当前处于打开状态的文件,以便用同一个CFile对象打开另一个文件。

1.2读和写

      可以用CFile::Read读一个具有访问权的打开文件。可以用CFile::Write写一个具有写访问权的打开文件。下面的示例分配一个4KB的文件IO缓冲,并一次读取4KB内容,转换为小写字母后再写回文件。如下:

[cpp] view plaincopyprint?
  1. //创建文件并写入文件内容   
  2.     char ch[]="ABCDEFGHIJKLMN";  
  3.     CFile file("1.txt",CFile::modeCreate | CFile::modeReadWrite | CFile::modeNoTruncate);  
  4.     file.Write(ch,sizeof(ch));  
  5.     //注意:移动文件指针到文件开头   
  6.     file.SeekToBegin();  
  7.       
  8.     //接着读取文件内容到自己定义的缓冲区内   
  9.     BYTE buffer[0x1000];  
  10.     DWORD dwBytesRemaining=file.GetLength();  
  11.     while(dwBytesRemaining)  
  12.     {  
  13.         DWORD dwPosition=file.GetPosition();  
  14.         UINT nByteRead=file.Read(buffer,sizeof(buffer));  
  15.         ::CharLowerBuff((char*)buffer,nByteRead);  
  16.         file.Seek(dwPosition,CFile::begin);  
  17.         file.Write(buffer,nByteRead);  
  18.         dwBytesRemaining-=nByteRead;  
  19.     }  
  20.     MessageBox((char*)buffer);    
  21.     //最后关闭文件,也可以不用自己调用该函数,而由CFile的析构函数来做这个工作  
  22.     file.Close();  
 

      如果在文件IO过程中有错误发生,Read、Write、和其它CFile函数就会发送一个CFileException。CFileException::m_Cause告诉你引发错误的原因。例如:试图向已满的磁盘上写文件会引发CFileException,其中m_Cause等于CFileException::diskFull。试图在文件范围之外读取数据会引发CFileException,其中m_Cause等于CFileException::endOfFile.

      如果你不捕获CFile成员函数发送的异常,MFC会替你捕获它们。MFC给未处理的异常配有默认处理程序,该程序调用ReportError显示一条描述错误的信息。然而,一般情况下,最好捕获文件IO异常,防止代码的关键部分被遗漏

 

例:

CString    strFileName = “D:\\bak\\test.txt”;

TRY

{

       CFile f(strFileName,CFile::modeCreate | CFile::modeWrite);

}

CATCH( CFileException e )

{

       if( e->m_cause == CFileException::fileNotFound )

                     printf( "ERROR: File not found\n");

       else if( e->m_cause == CFileException:: diskFull)

                     printf( "ERROR: Disk full\n");

       else if( e->m_cause == CFileException:: endOfFile)

                     printf( "ERROR: End Of File\n");

}

注:

m_cause可能为以下值

CFileException::none:          没有错误发生。

CFileException::generic:       未指定的错误。

CFileException::fileNotFound :    文件找不到错误。

CFileException::badPath :    全部或部分路径无效。

CFileException::tooManyOpenFiles:超出允许打开的文件数目。

CFileException::accessDenied :   不能访问文件。

CFileException::invalidFile :        试图访问一个无效的文件。

CFileException::removeCurrentDir:试图删除正在操作的目录。

CFileException::directoryFull:         目录个数已满。

CFileException::badSeek :      试图设置文件位置指针出错。

CFileException::hardIO :        硬件出错。

CFileException::sharingViolation : 共享出错。

CFileException::lockViolation :       试图锁定已锁定的区域。

CFileException::diskFull :               磁盘空间已满。

CFileException::endOfFile :           到达文件结尾。

 

 

原创粉丝点击