(Windows编程 文件专题)打开,读取,写入和关闭文件
关键词
C++ CreateFile CloseHandle ReadFile WriteFile API 文件句柄
◆CreateFile
HANDLE CreateFile(
LPCTSTR lpName,
DWORD dwAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreate,
DWORD dwAttrsAndFlags,
HANDLE hTemplateFile)
返回值:所创建文件对象的句柄,如果文件创建失败则返回
INVALID_HANDLE_VALUE
lpName 是以null结尾的对文件,管道或其他打开和创建的命名对象进行命名的字符串的指针.
dwAccess 使用 GENERIC_READ 和 GENERIC_WRITE 来指定读写访问(见WINNT.H中宏定义),允许使用位操作符(或)合并
dwShareMode是以下二进制方式的(或)操作
● 0——文件不能共享,甚至该进程不能打开该文件的第二个句柄
● FILE_SHARE_READ——其他进程包括调用进程可以打开该文件进行并发读访问
● FILE_SHARE_WRITE——它允许对文件进行并发写操作
lpSecurityAttributes 指向了 SECRITY_ATTRIBUTES 结构。
dwCreate指定了是否创建一个新的文件,是否重写现有的文件等等,允许(或)操作
● CREATE_NEW——如果指定的文件已经存在,操作失败,否则创建新的文件
● CREATE_ALWAYS ——现有的文件将被改写
● OPEN_EXISTING——如果文件不存在,操作失败
● OPEN_ALWAYS——打开文件,如果文件不存在则创建
● TRUNCATE_EXISTING——文件长度设为零,需要dwCreate指定GENERIC_WRITE,
如果文件已存在,所有内容将会破坏
dwAttrsAndFlags 指定了文件属性和标记。有16个标记和属性
● FILE_ATTRIBUTE_NORMAL 该属性只有在其他属性没有设置时才有用
● FILE_ATTRIBUTE_READONLY 程序不能改写也不能删除文件
● FILE_FLAG_DELETE_ON_CLOSE 对于临时文件很有用。
当最后一个HANDLE关闭时,文件就被删除
● FILE_FLAG_OVERLAPPED 该属性标记对于异步I/O很重要
● FILE_FLAG_WRITE_THROUGH 直接对磁盘文件进行中间缓存写操作
● FILE_FLAG_NO_BUFFERING 没有中间缓存,数据传输直接在程序中由 ReadFile和
WriteFile 调用指定的数据缓存上实现。相应地,在扇区地边界处也需要缓存,而且完
整地扇区必须被传输。在使用该标记时,通过调用函数 GetDiskFreeSpace 来决定扇
区的大小
● FILE_FLAG_RANDOM_ACCESS 主要用于随机访问,而 Windows 也会尽量优化文件
缓存
● FILE_FLAG_SEQUENTIAL_SCAN 主要用于顺序访问,而 Windows也会对文件缓存作
相应优化
hTemplateFile 是打开的 GENERIC_READ 文件的句柄,该文件指定了用于新创建的文件的扩展属性,并忽略了 dwAttrsAndFlags。通常参数是NULL,当现有的文件已打开时,hTemplateFile 被忽略。该参数可用来将新文件的属性设置成跟现有文件的属性相同
如果文件共享属性和安全性允许,文件会有许多打开的句柄。打开的句柄可以由相同或不同的进程所拥有
◆关闭文件
BOOL CloseHandle(HANDLE hObject)
返回值:如果本函数成功执行,返回TRUE,否则返回FALSE。
一个万能的函数关闭,句柄会销毁,所有对象的系统资源也会释放。当然也会有异常情况。关闭句柄也减少了对象的句柄引用计数,这样非永久的对象比如临时文件和事件将被删除。系统在退出时会关闭所有打开句柄,但是在程序终止前关闭其句柄是个很好的习惯。
关闭一个无效的句柄或对同一个句柄关闭两次将会引起异常,而关闭标准设备句柄是不必要的或不适宜的
◆读取文件
BOOL ReadFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped)
返回值:如果文件读取操作成功执行,则返回TRUE(即使试图读取文件末尾后的内容,未能读取到任何字节,仍旧返回TRUE)。
hFile 是具有GENERIC_READ 访问权限的文件句柄。
lpBuffer指向接受输入数据的内存缓存
nNumberOfBytesToRead 是从文件中读取的字节数,如果句柄位于文件的末尾处或有错误时,其值可以是零。消息模式的命名管道允许0长度的消息。
lpOverlapped 指向了OVERLAPPED结构,现在使用NULL
如果dwAttrsAndFlags中没有设置选项 FILE_FLAG_OVERLAPPED。那么ReadFile从句柄的当前文件位置开始,随着传输字节数往前移动位置。
如果句柄或任何其它参数无效,函数失败并返回FALSE,如果文件句柄位于文件末尾处,函数不会失败,取而代之,读取字节数 (*lpNumberOfBytesRead)被设为0。
◆写文件
BOOL WriteFile(
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped)
返回值:如果本函数成功执行,则返回TRUE,否则返回FALSE
注意一个成功的写操作不能确保数据真正被写入硬盘中,除非在CreateFile中指定FILE_FLAG_WRITE_THROUGH。如果句柄位于文件的末尾,Windows会扩展现有的文件的长度。
ReadFileGather 和WriteFileGather 允许使用不同大小的缓存来进行读写操作。
附:
示例文件(CPW.cpp)
/* 使用Windows API 实现文件复制 */
/* cpw.cpp */
#include <windows.h>
#include <stdio.h>
#define BUF_SIZE 256
int main(int argc,LPTSTR argv[]){
HANDLE hIn,hOut;
DWORD nIn,nOut;
CHAR Buffer[BUF_SIZE];
if(argc != 3){
printf("Usage:cpw file1 file2\n");
return 1;
}
hIn = CreateFile(argv[1],GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);
if (hIn == INVALID_HANDLE_VALUE){
printf("Can't open input file.Error:%x\n",GetLastError());
return 2;
}
hOut = CreateFile(argv[2],GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if (hOut == INVALID_HANDLE_VALUE){
printf("Can't open output file.Error:%x\n",GetLastError());
return 3;
}
while(ReadFile(hIn,Buffer,BUF_SIZE,&nIn,NULL) && nIn>0){
WriteFile(hOut,Buffer,nIn,&nOut,NULL);
if(nIn != nOut){
printf("Fatal write error:%x\n",GetLastError());
return 4;
}
}
CloseHandle(hIn);
CloseHandle(hOut);
return 0;
}