《Windows核心编程》---文件操作

Windows提供了一类API来读、写和管理磁盘文件。

使用API函数读写文件时,首先要使用CreateFile函数创建文件对象,调用成功会返回文件句柄。我们以此句柄为参数调用ReadFileWriteFile函数,进行实际的读写操作;最后调用CloseHandle函数关闭不再使用的文件对象句柄。

 

1)打开和关闭文件:

CreateFile是一个功能强大的函数,Windows下的底层设备几乎都由它打开。它可以创建或打开文件、目录、物理磁盘、控制台缓冲区、油槽或管道等:

HANDLE CreateFile(

         LPCTSTR lpFileName,  //要创建或打开的对象的名称

         DWORD dwDesiredAccess, //文件的存取方式

         DWORD dwShareMode,               //共享属性

         LPSECURITY_ATTRIBUTES lpSecurityAttributes,      //安全属性

         DWORD dwCreationDisposition,                //文件存在或不存在时系统采取的行动

         DWORD dwFlagsAndAttributes,         //新文件的属性

         HANDLE hTemplateFile       //一个文件模板的句柄

         );

lpFileName—如果是打开文件,直接指定文件名称即可;如果操作对象是第一个串口,则指定“COM1”为文件名,然后就可以像操作文件一样操作串口了;如果要打开本地电脑上的一个服务,要以//./服务名称为文件名,其中”.”代表本地机器;如果要打开网络中其他主机的文件,则以//主机名/共享目录名/文件名为文件名。

dwDesiredAccessGENERIC_READ(只读)GENERIC_WRITE(只写)、两者组合。

dwShareMode—表示文件打开后是否允许其他代码以某种方式再次打开这个文件,可以是下面的组合:

         0—不允许文件再被打开。C语言中的fopen函数就是这种方式;

         FILE_SHARE_DELETE—允许其他程序代码删除文件;

         FILE_SHARE_READ—允许其他程序代码以读方式打开文件;

         FILE_SHARE_WRITE—允许其他程序代码以写方式打开文件;

dwCreationDisposition—指定当文件已存在或不存在时系统采取的动作:

         CREATE_ALWAYS—创建新文件,若文件存在,则覆盖它,清除存在的属性;

         CREATE_NEW—创建新文件。若文件存在,函数执行失败;

         OPEN_ALWAYS—如果文件存在则打开它,不存在则创建新文件;

         OPEN_EXISTING—打开存在的文件。若文件不存在,函数执行失败;

         TRUNCATE_EXISTING—打开文件并将文件截断为0,当文件不存在时函数执行失败。

dwFlagsAndAttributes—指定新建文件属性和标志,可以是以下各项的组合:

         FILE_ATTRIBUTE_ARCHIVE—标记归档属性;

         FILE_ATTRIBUTE_HIDDEN—标记隐藏属性;

         FILE_ATTRIBUTE_READONLY—标记只读属性;

         FILE_ATTRIBUTE_SYSTEM—标记系统属性;

                FILE_ATTRIBUTE_TEMPORARY—临时文件,操作系统会尽量把所有文件的内容保持在内存中以加快存取速度。使用完后要尽快将它删除。

         FILE_FLAG_DELETE_ON_CLOSE—文件关闭后系统立即自动删除它;

         FILE_FLAG_OVERLAPPED—使用异步读写文件的方式;

         FILE_FLAG_WRITE_THROUGH—系统不会对文件使用缓冲,文件的任何改变都会被系统立即写入硬盘。

hTemplateFile—指定一个文件模板句柄。系统会复制文件模板的所有属性到当前创建的文件中。

 

打开或创建文件成功时,函数返回文件句柄,失败时返回INVALID_HANDLE_VALUE

 

2)移动文件指针:

SetFilePointer函数:系统为每个打开的文件维护一个文件指针,指定对文件的下一个读写操作从什么位置开始。随着数据的读出或写入,文件指针也随之移动。当文件刚被打开时,文件指针处于文件的头部。有时候需要随机读取文件内容,这就需要先调整文件指针:

DWORD SetFilePointer(

         HANDLE hFile,                //文件句柄

         LONG lDistanceToMove,    //要移动的距离

         PLONG lpDistanceToMoveHigh,        //移动距离的高32位,一般位置为NULL

         DWORD dwMoveMethod           //移动的模式

         );

dwMoveMethod参数指明从什么地方开始移动:

         FILE_BEGIN—开始移动的位置为0,即从文件头部开始移动;

         FILE_CURRENT—开始移动位置是文件指针的当前值;

         FILE_END—开始移动位置是文件的结尾,即从文件尾开始移动。

文件指针也可以移动到所有数据后面,比如现在文件长度是200KB,但可以成功地将文件指针移动到1000KB的位置。这样做可以达到扩展文件长度的目的。

SetEndOfFile函数就可以达到截断或者扩展文件的功能。该函数移动指定文件的结束标志(EOF)到文件指针指向的位置。如果文件扩展,旧的EOF位置和新的EOF位置间的内容是未定义的:

BOOL SetEndOfFile(HANDLE hFile);

截断或者扩展文件时,要首先调用SetFilePointer移动文件指针,然后再调用SetFilePointer函数设置新的文件指针位置为EOF

 

3)读写文件:

ReadFileWriteFile函数既可以同步读写文件,也可以异步读写文件;而函数ReadFileExWriteFileEx只能异步读写文件。

BOOL ReadFile(

         HANDLE hFile,                //文件句柄

         LPVOID lpBuffer,  //指向一个缓冲区,函数会将读出的数据返回到这里

         DWORD nNumberOfBytesToRead,   //要求读入的字节数

         LPDWORD lpNumberOfBytesRead,  //指向一个DWORD类型的变量,用于返回实际读入的字节数

         LPOVERLAPPED lpOverlapped  //一般设为NULL

         );

 

BOOL WriteFile(

         HANDLE hFile,                //文件句柄

         LPVOID lpBuffer,  //指向一个缓冲区,包含了要写入文件的数据

         DWORD nNumberOfBytesToWrite, //要求写入的字节数

         LPDWORD lpNumberOfBytesWritten,     //指向一个DWORD类型的变量,用于返回实际写入的字节数

         LPOVERLAPPED lpOverlapped  //一般设为NULL

         );

使用WriteFile写文件时,写入的数据通常被Windows暂存在内部的高速缓存中,等合适的时候再一并写入磁盘。可以使用FlushFileBuffers函数来强制系统清空缓冲区:

BOOL FlushFileBuffers(HANDLE hFile);

 

4)锁定文件:

当我们对文件数据的一致性要求较高时,为了防止程序在写入过程中其他进程刚好在读取写入区域的数据,可以对已打开文件的某个部分加锁,加锁和解锁的函数分别是LockFileUnlockFile

BOOL LockFile(

         HANDLE hFile,       //文件句柄

         DWORD dwFileOffsetLow,         //加锁的开始位置

         DWORD dwFileOffsetHigh,

         DWORD nNumberOfBytesToLockLow,    //加锁区域的大小

         DWORD nNumberOfBytesToLockHigh

         );

 

BOOL UnlockFile(

         HANDLE hFile,       //文件句柄

         DWORD dwFileOffsetLow,         //解锁的开始位置

         DWORD dwFileOffsetHigh,

         DWORD nNumberOfBytesToLockLow, //解锁区域的大小

         DWORD nNumberOfBytesToLockHigh

         );

 

5)获取文件类型:

Windows下许多对象都称为文件,如果想知道一个文件句柄到底是什么对象,可是使用函数GetFileType

DWORD GetFileType(HANDLE hFile);

返回值如下:

FILE_TYPE_CHAR---指定文件时字符文件,通常是LPT设备或控制台;

FILE_TYPE_DISK---指定文件时磁盘文件;

FILE_TYPE_PIPE---指定文件是套接字,一个命名的或未命名的管道;

FILE_TYPE_UNKNOWN—不能识别指定文件,或者函数调用失败。

 

获取文件大小:

如果确定操作的对象时磁盘文件,可以使用GetFileSize函数取得这个文件的长度:

DWORD GetFileSize(

         HANDLE hFile,                //文件句柄

         LPDWORD lpFileSizeHigh   //用于返回文件长度的高字节,可以指定这个参数为NULL

         );

函数执行成功将返回文件大小的低双字,如果lpFileSizeHigh不为NULL,函数将文件大小的高双字放入它指向的DWORD变量中。

如果返回值是INVALID_FILE_SIZE,应用程序必须调用GetLastError来确定函数调用是否成功。因为当lpFileSizeHigh不为NULL或者文件大小为oxffffffff时,函数虽然调用成功,但依然会返回INVALID_FILE_SIZE,这种情况下,GetLastError会返回NO_ERROR来响应成功。

 

6)获取文件属性:

如果要查看文件或者目录的属性,可以使用GetFileAttributes函数,它返回一系列FAT风格的属性信息:

DWORD GetFileAttributes(LPCTSTR lpFileName); //lpFileName指定了文件或者目录的名称

返回值是下列各项的组合:

FILE_ATTRIBUTE_ARCHIVE

FILE_ATTRIBUTE_COMPRESSED

FILE_ATTRIBUTE_DIRECTORY

FILE_ATTRIBUTE_HIDDEN

FILE_ATTRIBUTE_NORMAL

FILE_ATTRIBUTE_READONLY

FILE_ATTRIBUTE_SYSTEM

FILE_ATTRIBUTE_TEMPORARY

这些属性对目录同样适用,函数执行失败返回INVALID_FILE_ATTRIBUTES

设置文件属性的函数是SetFileAttributes

BOOL SetFileAttributes(

         LPCTSTR lpFileName,            //目标文件名称

         DWORD dwFileAttributes  //要设置的属性值

         );

下面是快速检查某个文件或目录是否存在的自定义函数:

BOOL FileExists(LPCTSTR lpszFileName, BOOL bIsDirCheck)

{

         //取得文件的属性

         DWORD dwAttributes = GetFileAttributes(lpszFileName);

         if(dwAttributes == INVALID_FILE_ATTRIBUTES)

         {

                   return FALSE;

         }

         if((dwAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)

         {

                   if(bIsDirCheck)       //检查目录

                            return TRUE;

                   else

                            return FALSE;

         }

         else

         {

                   if(!bIsDirCheck) //检查文件

                            return TRUE;

                   else

                            return FALSE;

         }

}

 

7)拷贝文件:

函数CopyFileCopyFileEx的作用是复制一个存在的文件到一个新文件中:

BOOL CopyFile(

         LPCTSTR lpExistingFileName,     //指定已存在的文件的名称

         LPCTSTR lpNewFileName,  //指定新文件的名称

         BOOL bFailIfExists                  //如果指定的新文件存在是否按出错处理

         );

CopyFileEx函数的附加功能是允许指定一个回调函数,在拷贝过程中,函数每拷贝完一部分数据,就会调用回调函数。用户在回调函数中可以指定是否停止拷贝,还可以显示进度条来指示拷贝的进度。

 

8)删除文件:

BOOL DeleteFile(LPCTSTR lpFileName);

DeleteFile函数删除的文件不会被放进回收站,它们将永远丢失。

自定义函数RecursiveDelete用于删除指定目录下所有的文件和子目录:

void RecursiveDelete(CString szPath)

{

         CFileFind ff;    //MFC将查找文件的API封装到了CFileFind类中

         CString strPath = szPath;

         //说明要查找此目录下的所有文件

         if(strPath.Right(1) != "//")

                   strPath += "//";

         strPath += "*.*";

         BOOL bRet;

         if(ff.FindFile(strPath))

         {

                   do

                   {

                            bRet = ff.FindNextFile();

                            if(ff.IsDots())  //目录为"."或者".."

                                     continue;

                            strPath = ff.GetFilePath();

                            if(!ff.IsDirectory()) //是文件了

                            {

                                     //删除此文件

                                     ::SetFileAttributes(strPath, FILE_ATTRIBUTE_NORMAL);

                                     ::DeleteFile(strPath);   

                            }

                            else  //还是目录

                            {       

                                     //递归调用

                                     RecursiveDelete(strPath);

                                     //删除此目录(RemoveDirectory只能删除空目录)

                                     ::SetFileAttributes(strPath, FILE_ATTRIBUTE_NORMAL);

                                     ::RemoveDirectory(strPath);

                            }

                   }while(bRet);         

         }

}

 

9)移动文件:

函数MoveFileMoveFileEx的功能是移动一个存在的文件或目录:

BOOL MoveFile(

       LPCTSTR lpExistingFileName, //存在的文件或目录

       LPCTSTR lpNewFileName      //新的文件或目录

       );           

当需要指定如何移动文件时,使用MoveFileEx

BOOL MoveFileEx(

       LPCTSTR lpExistingFileName, //存在的文件或目录

       LPCTSTR lpNewFileName,     //新的文件或目录

       DWORD dwFlags

       );           

dwFlags参数是下列值的组合:

MOVEFILE_DELAY_UNTIL_REBOOT函数并不立即执行,而是在操作系统下一次重启时才移动此文件。在AUTOCHK执行之后,系统立即移动文件,这是在创建任何分页文件之前进行的。因此,这个值能够使函数删除上一次运行时使用的分页文件。

MOVEFILE_REPLACE_EXISTING如果目标文件已存在的话,就将它替换掉;

MOVEFILE_WRITE_THROUGH直到文件实际从磁盘移除之后函数才返回。

posted on 2010-06-14 15:03  android开发实例  阅读(1329)  评论(0编辑  收藏  举报

导航