目前位置: VCer资源中心 >>> VCer文章 >>> C++/MFC基础

[本帖已阅读5169次 分值100 回复0次] 张贴资源 发回信箱 控制面板

解读VC++编程中的文件操作API和CFile类

提供者:iter 张贴时间:2007-03-13 14:32:17.0 出处:news.newhua.com 作者:不祥

解读VC++编程中的文件操作API和CFile类(2007-03-13 14:32:17.0)


烧香的熊猫


 
级别: VCer连长
头衔: VCer会员

经验: 2249
作品: 43
分会: 华北分会
注册: 2007-03-02 10:31:29.0
登录: 2008-02-09 20:02:01.0

在VC编程中,操作文件的方法主要有两种:利用API函数和MFC的CFile类。微软在其中封装了文件的一般操作,下面我就介绍一下如何利用这两种方法实现文件操作。

1.创建或打开一个文件

API函数CreateFile可打开和创建文件、管道、邮槽、通信服务、设备以及控制台,但是在此时只是介绍用这个函数怎么实现创建和打开一个文件。

文件的操作属性:如果为零,表示只允许获取与一个设备有关的信息,GENERIC_READ 表示允许对设备进行读访问;如果为 GENERIC_WRITE 表示允许对设备进行写访问(可组合使用);

文件的共享属性:零表示不共享; FILE_SHARE_READ 或 FILE_SHARE_WRITE 表示允许对文件进行读/写共享访问;

文件的操作有:

文件属性有:

操作系统不得推迟对文件的写操作

可以组合的属性有:FILE_FLAG_WRITE_THROUGH,FILE_FLAG_OVERLAPPED,FILE_FLAG_NO_BUFFERING,FILE_FLAG_RANDOM_ACCESS,FILE_FLAG_SEQUENTIAL_SCAN,FILE_FLAG_DELETE_ON_CLOSE,FILE_FLAG_BACKUP_SEMANTICS,FILE_FLAG_POSIX_SEMANTICS,FILE_FLAG_OPEN_REPARSE_POINT,FILE_FLAG_OPEN_NO_RECALL

如果成功返回一个打开文件得句柄,如果调用函数之前文件存在,文件操作属性为:CREATE_ALWAYS 或 OPEN_ALWAYS,使用GetLastError函数返回的是ERROR_ALREADY_EXISTS(包括函数操作成功),如果之前函数不存在,则返回0。使用失败返回INVALID_HANDLE_VALUE,要取得更多的信息,使用GetLastError函数。

文件关闭用:

例子1、在当前目录下面创建一个文件:

可以改变上面的创建文件的属性和操作看下不同效果。

CFile创建和打开一个文件:

创建文件和打开文件的方法有很多种,下面简单介绍下几个构造函数:

lpszFileName:文件名称,可以是相对路径,绝对路径或网络路径

nOpenFlags:打开方式有:

下面给出MSDN中的一个例子:

2.文件的读写定位

定位文件中的数据是很重要的,这决定了写入的数据在文件中的位置。API函数

dwMoveMethod文件定位的方式有三种:

此函数可以用来定位大型文件,lpDistanceToMoveHigh是高32位,lDistanceToMove是低32位。如果lpDistanceToMoveHigh为NULL时,函数操作成功,返回的是当前文件数据的偏移量,如果lpDistanceToMoveHigh不NULL,则返回数据的偏移量高32位放在 lpDistanceToMoveHigh中,函数调用失败返回的是0xffffffff.

CFile类的文件数据定位函数有:

如果要求的位置合法,则Seek返回从文件开始起的新字节偏移量

lOff:指针移动的字节数。

nFrom:指针移动的模式。可以是CFile::begin,CFile::current,CFile::end

void SeekToBegin( );

DWORD SeekToEnd( );//返回文件长度(字节数)。

下面是一个读取位图文件的信息的例子:

读取数据:

CFile的成员函数有:

UINT Read (void* lpBuf,UINT nCount);

throw(CFileException);// 返回值是传输到缓冲区的字节数。

写入数据:

lpBuf:指向用户提供的缓冲区,包含将写入文件中的数据

nCount:从缓冲区内传输的字节数。对文本模式的文件,回车换行作为一个字符。

下面是象一个文件中写入数据的例子:

3.取得和设置文件的创建时间、最后访问时间、最后写时间

取得三个参数都是FILETIME结构,得到的都是UTC时间,可以通过API函数FileTimeToLocalFileTime()和FileTimeToSystemTime()将他们转换为本地时间和系统时间格式,也可以通过LocalFileTimeToFileTime 和SystemTimeToFileTime()转换回来,通过SetFileTime设置文件的创建时间、最后访问时间、最后写时间。由于使用的时候要先打开文件,而且取得的最后访问时间就是当前时间,没有多大意义,且比较麻烦,下面介绍CFile类中的静态方法。

tatic BOOL PASCAL GetStatus( LPCTSTR lpszFileName, CFileStatus& rStatus );

tatic void SetStatus( LPCTSTR lpszFileName, const CFileStatus& status );

throw( CFileException );

返回的是一个CfileStatus对象,这个结构的具体的成员变量包括:

 

下面就举一个例子来实现:

 

4.取得和设置文件的属性

 

取得的文件属性包括:FILE_ATTRIBUTE_ARCHIVE,FILE_ATTRIBUTE_HIDDEN,FILE_ATTRIBUTE_NORMAL,FILE_ATTRIBUTE_OFFLINE,FILE_ATTRIBUTE_READONLY,FILE_ATTRIBUTE_SYSTEM,FILE_ATTRIBUTE_TEMPORARY

不能设置的文件属性包括有:FILE_ATTRIBUTE_COMPRESSED,FILE_ATTRIBUTE_DIRECTORY,FILE_ATTRIBUTE_ENCRYPTED,FILE_ATTRIBUTE_REPARSE_POINT,FILE_ATTRIBUTE_SPARSE_FILE,FILE_ATTRIBUTE_SYSTEM。

CFileStatus中也定义了一组属性:

可以通过if((status. m_attribute& readOnly) = =FILE_ATTRIBUTE_READONLY)来判断,这里利用另外的API来实现获得文件的详细信息:

HANDLE FindFirstFile(

LPCTSTR lpFileName, //文件或文件夹路经r

LPWIN32_FIND_DATA lpFindFileData

);

BOOL FindNextFile(

HANDLE hFindFile,

LPWIN32_FIND_DATA lpFindFileData

);

BOOL FindClose(HANDLE hFindFile );

取得的是一个WIN32_FIND_DATA结构;

也可以利用另外一个函数来取得文件的信息:

BOOL GetFileInformationByHandle(

HANDLE hFile, // 文件的句柄

LPBY_HANDLE_FILE_INFORMATION lpFileInformation

);

函数填充的是BY_HANDLE_FILE_INFORMATION结构体:

typedef struct _BY_HANDLE_FILE_INFORMATION {

DWORD dwFileAttributes;

FILETIME ftCreationTime;

FILETIME ftLastAccessTime;

FILETIME ftLastWriteTime;

DWORD dwVolumeSerialNumber; // 文件所在的磁盘的序列号

DWORD nFileSizeHigh;

DWORD nFileSizeLow;

DWORD nNumberOfLinks; //链接的数目

DWORD nFileIndexHigh;

DWORD nFileIndexLow;

} BY_HANDLE_FILE_INFORMATION;

下面就举一个例子来实现:

HANDLE handle;

WIN32_FIND_DATA find_data;

handle = :: FindFirstFile("D:\VSS",&find_data);

FindClose(handle);

find_data.dwFileAttributes = find_data.dwFileAttributes|FILE_ATTRIBUTE_READONLY;

::SetFileAttributes("D:\VSS",find_data.dwFileAttributes);

在上面的介绍中,除了可以设置文件的属性之外,在操作的过程当中也可以取得文件的其他一些信息,可以根据具体的需要来实现。 5.获取文件名,文件类型,文件长度,文件路径

用利用CFile打开一个文件时,可以在利用成员函数

virtual CString GetFileName( ) const,

virtual CString GetFileTitle( ) const,

virtual CString GetFilePath( ) const,

virtual DWORD GetLength( ) const;throw( CFileException );

来取得相关信息,如果一个文件的全路经是: c:\windows\write\myfile.wri,则每个函数取得的是: myfile.wri, myfile, c:\windows\write\myfile.wri. GetLength取得文件大小是按字节为单位的。

也可以利用:

virtual void SetLength( DWORD dwNewLen );throw( CFileException );

virtual void SetFilePath( LPCTSTR lpszNewName );

来设置文件的长度和路径。

在当前的文件下面新建一个Text.txt文件,在里面写点东西,然后运行下面程序:

CFile file("Text.txt",CFile::modeReadWrite);

ULONGLONG length;

CString strFilePath;

length = file.GetLength();

length = length + 1024*10;

file.SetLength(length);

file.SetFilePath("D:\Text.txt");

trFilePath = file.GetFilePath();

MessageBox(strFilePath);

file.Close();

最后发现文件的路径变了,但是在D盘下面并没有找到Text.txt,原因是SetFilePath只能指定一个路径给文件,SetFilePath并不能做为移动文件来使用。

CFile并没有给出取得文件类型的函数,有了上面基础,这个很容易实现。

API函数中也有获得文件路径的操作,这里只是做简单介绍,可以参照MSDNN的说明:GetFileSize可以获得文件的大小,GetFullPathName 函数获取文件的完整路径名,只有当该文件在当前目录下,结果才正确。GetModuleFileName函数获取文件的完整路径名,这些函数有些用到文件句柄的。

用CFileDialog打开的文件,可以使用它的成员变量m_ofn,或者成员函数GetFileName, GetFileTitle, GetFilePath, GetFileExt来取得相关信息.

CFileDialog( BOOL bOpenFileDialog, LPCTSTR lpszDefExt = NULL, LPCTSTR lpszFileName = NULL, DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, LPCTSTR lpszFilter = NULL, CWnd* pParentWnd = NULL );

各个参数如下:

?bOpenFileDialog 为TRUE为打开对话框,为FALSE为保存对话文件对话框

?lpszDefExt 指定默认的文件扩展名。

?lpszFileName 指定默认的文件名。

?dwFlags 指明一些特定风格。

?lpszFilter它指明可供选择的文件类型和相应的扩展名。参数格式如:

"Chart Files (*.xlc)|*.xlc|Worksheet Files (*.xls)|*.xls|Data Files (*.xlc;*.xls)|*.xlc; *.xls|All Files (*.*)|*.*||";文件类型说明和扩展名间用 | 分隔,同种类型文件的扩展名间可以用 ; 分割,每种文件类型间用 | 分隔,末尾用 || 指明。

pParentWnd 为父窗口指针

CString FileFilter = "所有文件(*.*)|*.*||";

CFileDialog FileDialog(true,NULL,NULL,OFN_HIDEREADONLY,FileFilter,NULL);

FileDialog.DoModal();

MessageBox(FileDialog.GetFileName());

6.小结

在实际中还有很多其他操作文件的方法,上面介绍的只是简单的几种,希望通过上面的简单介绍,在加上具体实践,能够找到解决问题的最好办法!

注:转载文章需注明来源:VCer.net 文章地址:http://vcer.net/1173767537140.html

  如果你觉得VCer.net不错,而且你愿意为VCer.net捐赠一元钱,那么点击后面的捐赠按钮吧:) vcer.net捐赠

[回复该贴] [加入个人书签]
[投票结果]

A: 评分 10 100% (2 票)
B: 评分 5 0% (0 票)
C: 评分 0 0% (0 票)
D: 评分 -5 0% (0 票)
E: 评分 -10 0% (0 票)