[WinAPI] API 10 [创建、打开、读写文件,获取文件大小]

在Windows系统中,创建和打开文件都是使用API函数CreateFile,CreateFile通过指定不同的参数来表示是新建一个文件,打开已经存在的文件,还是重新建立文件等。读写文件最为直接的方式是使用ReadFile和WriteFile函数,也可以使用文件镜像,获取文件大小一般使用GetFileSize函数,也可以使用GetFileAttributesEx等函数(在上节介绍)。读写文件、获取文件大小之前都需要使用CreateFile创建或打开的文件,获得文件句柄。
在文件操作中,文件句柄是一个关键的概念。文件句柄惟一标识了一个文件,ReadFile、WriteFile、GetFileSize等函数是使用文件句柄作为参数来表示,用户需要读、写、获取大小的文件是哪一个文件。在对文件进行操作前,都必须要使用CreateFile获得文件句柄。

(1)CreateFile
CreateFile是文件操作中最主要的一个函数。几乎所有的文件操作都需要使用到文件句柄。而CreateFile函数为这些操作建立文件句柄。CreateFile函数的参数多,而且比较复杂,涉及文件名、文件的共享模式、存取方式、操作模式、权限、标志和文件属性等。每一个参数都可以有多种值可供选择,代表了不同的意义。

◇参数
lpFileName:输入参数,操作对象文件的相对路径或绝对路径。
dwDesiredAccess:输入参数,指明对文件对象的操作存取方式,可以是GENERIC_READ,表示需要读文件;可以是GENERIC_WRITE,表示需要写文件;也可以是GENERIC_READGENERIC_WRITE,表示既可以读也可以写。
dwShareMode:输入参数,共享模式。指明与其他进程是否共享该文件,可以是共享读(FILE_SHARE DELETE)、共享写(FILE_SHARE_WRITE)、共享删除(FILE_SHARE.READ),如果要指明多个属性,使用“位与~‘I”运算。如果指明上述参数,其他进程就可以对文件进行相关操作。如果本进程需要独占本文件,则将本参数设置为0。
lpSecurityAttributes:指向SECURITY_ATTRIBUTES结构的指针,表示本文件句柄的安全属性,能影响其是否可被子进程继承等操作。如果设定为NULL,则子进程不可继承本句柄。SECURITY ATTRIBUTES结构不常用,对此数据结构的设置,涉及Windows系统中对权限管理的原理,在本章中不作详细说明。
dwCreationDisposition:输入参数,操作模式。

dwFlagsAndAttributes:输入参数,文件属性和文件标志

一般情况下文件属性较常用,而操作标志不常用,可以使用“1”运算符指定多个属性和标志。
hTemplateFile:输入参数,当存取权限包括GENERIC_WRITE时,可以设置为一个模板文件的句柄。一般情况下,可设置为NULL,表示不使用模板文件。
◇返回值
返回HANDLE数据类型值,表示文件的句柄,如果返回INVALID_HANDLE_VALUE,表示操作失败。

(2)ReadFile。
ReadFile动能是从文件中读出数据。需要使用CreateFile所返回的文件句柄。

◇参数
hFile:输入参数,读取数据的文件对象,由CreateFile创建,调用CreateFile打开文件时需要指明GENERIC_READ读取操作模式。
lpBuffer:输入参数,指向读取文件数据存储的内存缓冲区。
nNumberOfBytesToRead:输入参数,指明需要从文件中读出的数据的大小,不能大于lpBuffer内存块的大小,否则会造成溢出。
lpNumberOfBytesRead:输出参数,指向存储实际读出的数据大小的DWORD变量。在读文件时,可能由于已经到达文件尾等原因,其值可能小于rtNumberOfBytesToRead。如果lpOverlapped为NULL,则该参数不能为NULL。
lpOverlapped:输入参数,指向OVERLAPPED结构体的指针,如果调用CreateFile时设置了FILE_FLAG_OVERLAPPED标志,则需要使用该参数,否则可以为NULL。
◇返回值
返回BOOL值,表示读文件是否成功。
◇使用说明
在读的过程中,文件指针会随着读操作的进行而自动移动,在循环调用本函数时,会顺序读出文件的内容,如果程序返回失败,可以使用GetLastError函数获取错误信息。

(3)WriteFile。
WriteFile函数的功能是将数据写入到文件中,写入到文件指针所在的位置,写入操作完成后,文件指针会移动到写入的数据之后

◇参数
hFile:输入参数,写入数据的文件对象,由CreateFile创建,调用CreateFile打开文件时,需要指明GENERIC_WRITE读取操作模式。
lpBuffer:输入参数,指向需写入文件数据存储的内存缓冲区。
nNumberOBytesToWrite:输入参数,指明需要写入文件中的数据的大小。
lpNumberOiBytesWritten:输出参数,指向存储真实写入的数据大小的变量,可能由于已经到达文件尾等原因,其值可能与nNumberOfBytesToWrite不同。如果lpOverlapped为NULL,则该参数不能为NULL。
lpOverlapped:输入参数,指向OVERLAPPED结构体的指针,如果调用CreateFile时设置了FILE_FLAG_OVERIAPPED标志,则需要使用该参数。可以为NULL。
◇返回值
返回BOOL值,表示写文件是否成功。
◇使用说明

在读的过程中,文件指针会随着写操作的进行而移动,在循环调用本函数时,会按顺序写入文件内容。如果程序返回失败,可以使用 GetLastError函数获取错误信息。

(4)GetFileSize、GetFileSizeEX.
GetFileSize、GetFileSizeEX的功能是一致的,都是获取文件大小

◇参数
GetFileSize的参数如下。
hFile:输入参数,读取数据的文件对象,由CreateFile创建,调用CreateFile打开文件时需要指明GENERIC_READ读取操作模式或者GENERIC_WRITE写入操作模式。
lpFileSizeHigh:输出参数,表示得到的文件大小的高32位。该参数可以为NULL,为NULL时表示文件大小可以用DWORD表示。具体解释请参考返回值部分。
GetFileSizeEx的参数如下。
hFile:输入参数,读取数据的文件对象,由CreateFile创建,调用CreateFile打开文件时,需要指明GENERIC_READ读取操作模式或者GENERIC_WRITE写入操作模式。
lpFileSize:输出参数,指向储存文件大小的一个LARGE_ INTEGER联合体,前面已经介绍过了LARGE.1NTEGER结构的相关内容,参见API 9 小节关键数据结构部分。
◇返回值
GetFileSize成功时,返回值为一个表示文件大小DWORD值。
GetFileSize失败时,如果lpFileSizeHigh为NULL,返回INVALID_ FILE_SIZE并可以调用GetLastError函数获取更详细的错误信息;如果lpFileSizeHigh为非NULL,那么同样返回INVALID_FILE_SIZE并且尝试读取lpFileSizeHigh指向的值放在高32位,并将其和返回的低32位DWORD连起来成为一个64位的值来表示文件大小。lpFileSizeHigh为合法值则GetLastError返回NO_ERROR,表示该API仍然成功;否则,GetLastError返回一个不等于NO_ERROR的值。

GetFileSizeEx直接返回BOOL值,表示读文件是否成功。

◇使用说明
实际上这两个函数的区别就在于,对文件大小超出DWORD的情况采取不同处理方式。由于历史原因,GetFileSize用两个32位值来分别储存64位文件大小的高位和地位;而GetFileSizeEx直接将文件大小储存在64位的联合体中。

>>>本实例使用CreateFile、ReadFile、WriteFile来完成创建、打开、读写文件的功能。笔者在实例中自己编写一个SaveDataToFile函数在D盘根目录下建立一个show.txt并向文件中写入数据,并编写了一个ReadFileContent函数读取文件的内容。

 #include <Windows.h>
#include <stdio.h> DWORD ReadFileContent(LPSTR szFilePath)
{
//文件大小
HANDLE hFileRead;
//保存文件大小
LARGE_INTEGER liFileSize;
//成功读取的文件数据大小
DWORD dwReadedSize;
//累加计算已经读取的数据的大小
LONGLONG liTotalRead=;
//文件数据缓存
BYTE lpFileDataBuffer[]; //打开已经存在的文件,读取内容
hFileRead = CreateFileA(szFilePath,//name
GENERIC_READ, //以读方式打开
FILE_SHARE_READ, //可共享读
NULL, //默认安全设置
OPEN_EXISTING, //只打开已经存在的文件
FILE_ATTRIBUTE_NORMAL, //常规文件属性
NULL); //无模板
//打开文件是否成功
if(hFileRead==INVALID_HANDLE_VALUE)
{
printf("打开文件失败: %d",GetLastError());
}
if(!GetFileSizeEx(hFileRead,&liFileSize))
{
printf("获取文件大小失败: %d",GetLastError());
}
else
{
printf("文件大小为: %d\n",liFileSize.QuadPart);
}
//循环读取并打印内容
while(TRUE)
{
DWORD i;
if(!ReadFile(hFileRead,//读取文件句柄
lpFileDataBuffer, //存储读取文件内容
, //读取的大小(字节)
&dwReadedSize, //实际读取的大小
NULL)) //不使用Overlapped
{
printf("读取文件错误: %d\n",GetLastError());
break;
}
printf("读取了%d字节,文件内容是: ",dwReadedSize); for(i=;i<dwReadedSize;i++)
{
printf("0x%x ",lpFileDataBuffer[i]);
}
printf("\n");
liTotalRead+=dwReadedSize;
if(liTotalRead==liFileSize.QuadPart)
{
printf("读取文件结束\n");
break;
}
}
CloseHandle(hFileRead);
return ;
} DWORD SaveDataToFile(
LPSTR szFilePath,
LPVOID lpData,
DWORD dwDataSize)
{
//文件句柄
HANDLE hFileWrite;
//成功写入的数据大小
DWORD dwWritedDateSize;
//打开已经存在的文件,读取内容
hFileWrite=CreateFileA(szFilePath,//要打开的文件名
GENERIC_WRITE,//以写方式打开开
,//可共享读
NULL,//默认安全设置
OPEN_ALWAYS,//打开已经存在的文件
FILE_ATTRIBUTE_NORMAL,//常规属性打开
NULL);//无模板
//判断是否成功打开
if(hFileWrite==INVALID_HANDLE_VALUE)
{
printf("打开文件失败: %d\n",GetLastError());
}
//设置文件指针到文件为
SetFilePointer(hFileWrite,,,FILE_END);
//将数据写入文件
if(!WriteFile(hFileWrite,lpData,dwDataSize,&dwWritedDateSize,NULL))
{
printf("写文件失败: %d\n",GetLastError());
}
else
{
printf("写文件成功,写入%d字节。\n",dwWritedDateSize);
}
CloseHandle(hFileWrite);
return ;
}
int main()
{
LPSTR szFileData="这是一个例子";
SaveDataToFile("D:\\show.txt",szFileData,lstrlenA(szFileData));
ReadFileContent("D:\\show.txt");
return ;
}
上一篇:android 5.0 创建多用户 双开多开应用(1)


下一篇:Maven3路程(六)用Maven创建Spring3 MVC项目