Windows核心编程之文件操作.docx

上传人:b****5 文档编号:4576123 上传时间:2022-12-06 格式:DOCX 页数:29 大小:30.72KB
下载 相关 举报
Windows核心编程之文件操作.docx_第1页
第1页 / 共29页
Windows核心编程之文件操作.docx_第2页
第2页 / 共29页
Windows核心编程之文件操作.docx_第3页
第3页 / 共29页
Windows核心编程之文件操作.docx_第4页
第4页 / 共29页
Windows核心编程之文件操作.docx_第5页
第5页 / 共29页
点击查看更多>>
下载资源
资源描述

Windows核心编程之文件操作.docx

《Windows核心编程之文件操作.docx》由会员分享,可在线阅读,更多相关《Windows核心编程之文件操作.docx(29页珍藏版)》请在冰豆网上搜索。

Windows核心编程之文件操作.docx

Windows核心编程之文件操作

5.1磁盘文件的打开和关闭

本节主要讲述磁盘文件的打开和创建,在最后讲述一些对目录的操作。

在Win32下传统的ANSIC函数依然可以用来对函数进行操作,例如:

fopenfreadfwritefclose,但M$推荐使用CreateFile,CreateFile函数的用途很多(我最开始时候被这个函数的多用途吓住了),可以打开和创建下面的设备文件:

∙Consoles

∙Communicationsresources

∙Directories(只能打开)

∙Files

∙Mailslots

∙Pipes

关于管道的创建和打开已经在上章4.5节讲过了,本章主要讲如何对磁盘文件的打开和创建操作。

HANDLECreateFile(

LPCTSTRlpFileName,//filename

DWORDdwDesiredAccess,//accessmode

DWORDdwShareMode,//sharemode

LPSECURITY_ATTRIBUTESlpSecurityAttributes,//SD

DWORDdwCreationDisposition,//howtocreate

DWORDdwFlagsAndAttributes,//fileattributes

HANDLEhTemplateFile//handletotemplatefile

);

文件名lpFileName:

文件名的最大长度为MAX_PATH,文件可以为UNC,例如:

\\server\file_name可以指明网络上其他主机上的文件。

存取方法dwDesiredAccess:

可以通过指定参数表明打开文件读还是写,GENERIC_READ|GENERIC_WRITE表示一个文件进行读写。

DELETE表示删除文件。

共享属性dwShareMode:

表明文件打开后是否允许文件以某种存取方式(通过指定参数dwDesiredAccess的值)再次被打开,

∙0不允许文件再被打开

∙FILE_SHARE_DELETE允许其他进程在以后打开文件进行删除

∙FILE_SHARE_READ允许其他进程在以后打开文件进行读

∙FILE_SHARE_WRITE允许其他进程在以后打开文件进行写

安全描述lpSecurityAttributes:

通过指定安全描述参数可以指定返回的句柄是否可以被子进程继承,如果设置为NULL则表明无法被继承。

typedefstruct_SECURITY_ATTRIBUTES{

DWORDnLength;

LPVOIDlpSecurityDescriptor;

BOOLbInheritHandle;

}SECURITY_ATTRIBUTES,*PSECURITY_ATTRIBUTES;

在结构中设置nLength=sizeof(SECURITY_ATTRIBUTES),lpSecurityDescriptor=NULL,bInheritHandle=TRUE就可以使子进程能够集成句柄。

dwCreationDisposition用来设置文件在存在或不存在时系统采用的方法,可能的取值为:

∙CREATE_NEW:

创建新文件,当文件已经存在时函数会返回失败

∙CREATE_ALWAYS:

无论文件是否存在都创建新文件并且清楚原文件的所有属性

∙OPEN_EXISTING:

打开存在的文件,当文件不存在时函数会返回失败

∙OPEN_ALWAYS:

打开文件,当文件已经存在时函数会创建新文件

∙TRUNCATE_EXISTING:

打开文件并将文件截断为零,当文件不存在时函数会返回失败

文件属性和参数dwFlagsAndAttributes:

通过这个参数来指定创建的文件属性和打开文件时的参数,文件属性可以是下面这些值的合并:

∙FILE_ATTRIBUTE_NORMAL普通文件,设置这个属性时其他属性都不会生效

∙FILE_ATTRIBUTE_ARCHIVE归档文件

∙FILE_ATTRIBUTE_HIDDEN隐藏文件

∙FILE_ATTRIBUTE_READONLY只读文件

∙FILE_ATTRIBUTE_SYSTEM系统文件

∙FILE_ATTRIBUTE_TEMPORARY临时文件。

此外该参数还会指定文件操作的标记,可用的标记有下面这些:

∙FILE_FLAG_WRITE_THROUGH使用WriteThrough模式,系统不会对文件使用缓存,文件的改变马上会被写入到磁盘

∙FILE_FLAG_OVERLAPPED使用异步文件操作模式Win9X不支持异步操作

∙FILE_FLAG_DELETE_ON_CLOSE文件被关闭后立即删除文件

∙FILE_FLAG_RANDOM_ACCESS说明对文件进行随机读写操作,用于暗示操作系统对该文件的缓存使用进行优化

文件模板hTemplateFile:

当指定文件模板的句柄时该文件模板的所有属性会被复制到当前创建的文件。

CreateFile和ANSIC函数中fopen的比较:

操作

fopen

CreateFile

打开读

fopen("a.txt","r")

CreateFile("a.txt",GENERIC_READ,0,NULL,

OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL)

打开写并创建

fopen("a.txt","w")

CreateFile("a.txt",GENERIC_WRITE,0,NULL,

CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL)

打开读写

fopen("a.txt","r+")

CreateFile("a.txt",GENERIC_WRITE|GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL)

打开读写并创建

fopen("a.txt","w+")

CreateFile("a.txt",GENERIC_WRITE|GENERIC_READ,0,NULL,

CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL)

如果文件打开成功则返回文件句柄,否则返回INVALID_HANDLE_VALUE。

通过GetLastError来获取错误信息。

文件的关闭很简单,只需要用CloseHandle就可以关闭文件,当文件被关闭时所有缓存内数据都会被写入到磁盘。

文件的删除可以使用下面的函数,并指明文件名

BOOLDeleteFile(

LPCTSTRlpFileName//filename

);

对于目录的创建可以使用:

BOOLCreateDirectory(

LPCTSTRlpPathName,//directoryname

LPSECURITY_ATTRIBUTESlpSecurityAttributes//安全描述通常情况下设置为NULL

);

BOOLCreateDirectoryEx(

LPCTSTRlpTemplateDirectory,//templatedirectory

LPCTSTRlpNewDirectory,//directoryname

LPSECURITY_ATTRIBUTESlpSecurityAttributes//SD

);

后一个函数可以创建一个和现有目录具有相同属性的新目录。

如果要删除一个存在的目录可以使用

BOOLRemoveDirectory(

LPCTSTRlpPathName//directoryname

);

上面这些函数的返回值都是BOOL类型,可以通过返回值判断是否执行成功。

如果失败可以通过GetLastError得到错误信息

5.2磁盘文件的正常读写与异步读写

在Win32系统下文件可以支持平常的同步读写和异步读写(但在Win9X下,Win32系统不支持磁盘文件的异步读写)。

本节在后面部分将会介绍文件的异步读写,最后一段内容将向大家讲解一下文件的区域加锁。

在Win32系统中支持64位长度的文件,所以在很多文件操作函数中需要两个DWORD参数来表示文件长度,一个DWORD用来表示低32位,另一个用来表示高32位。

文件的读写进行在文件被正确打开后,但请确认在打开文件时设置了正确的读写标记。

在Win32的文件操作中没有了以前类似与以前ANSIC中的fputsfgetsfprintffscanf等函数,只有类似于fread和fwrite的ReadFile和WriteFile函数。

ReadFile用于文件读,函数原型为:

BOOLReadFile(

HANDLEhFile,//handletofile

LPVOIDlpBuffer,//databuffer

DWORDnNumberOfBytesToRead,//numberofbytestoread

LPDWORDlpNumberOfBytesRead,//numberofbytesread

LPOVERLAPPEDlpOverlapped//overlappedbuffer

);

其中各项参数的含义为:

∙hFile:

文件句柄,为CreateFile时返回的句柄

∙lpBuffer:

保存读入的数据的指针

∙nNumberOfBytesToRead:

指定需要读入的字节数

∙lpNumberOfBytesRead:

返回实际读入的字节数

∙lpOverlapped:

在文件异步读写时使用的数据,在同步读写中全部都设置为NULL,在Win9X中只支持对串口的异步操作。

如果返回值为FALSE并且读入的字节数也返回为0,则表示文件到达了末尾。

WriteFile用于文件写,函数原型为:

BOOLWriteFile(

HANDLEhFile,//handletofile

LPCVOIDlpBuffer,//databuffer

DWORDnNumberOfBytesToWrite,//numberofbytestowrite

LPDWORDlpNumberOfBytesWritten,//numberofbyteswritten

LPOVERLAPPEDlpOverlapped//overlappedbuffer

);

参数的含义和ReadFile类似。

如果需要移动文件指针到相关位置(和文件读写不同,这个函数没有异步版本),使用

DWORDSetFilePointer(

HANDLEhFile,//handletofile

LONGlDistanceToMove,//bytestomovepointer

PLONGlpDistanceToMoveHigh,//bytestomovepointer

DWORDdwMoveMethod//startingpoint

);

其中各项参数的含义为:

∙hFile:

文件句柄,为CreateFile时返回的句柄

∙lpBuffer:

保存读入的数据的指针

∙lDistanceToMove:

移动的字节数低DWORD

∙lpDistanceToMoveHigh:

移动的字节数高DWORD,为了支持64位(2的64次方字节)长度的大文件,而用来指定64字节的高32位,如果文件大小只需要32位就可以表示,则设置为NULL

∙ldwMoveMethod:

移动方法,可以选择下面的值。

FILE_BEGIN从文件开始处开始移动

FILE_CURRENT从文件开始除开始移动

FILE_END从文件末尾开始移动

函数返回值和参数lpDistanceToMoveHigh(当该参数不为NULL时)表明文件指针当前的位置(从文件头到当前的字节数),但当参数lpDistanceToMoveHigh为NULL时如果返回INVALID_SET_FILE_POINTER表明执行失败,当参数lpDistanceToMoveHigh不为NULL时如果返回INVALID_SET_FILE_POINTER还需要判断GetLastError的返回值是否不为NO_ERROR。

下面是两种情况下判断错误。

//第一种情况

DWORDdwPtr=SetFilePointer(hFile,lDistance,NULL,FILE_BEGIN);

if(dwPtr==INVALID_SET_FILE_POINTER)//Testforfailure

{

//Obtaintheerrorcode.

dwError=GetLastError();

//处理错误

//...

}//Endoferrorhandler

//第二种情况

dwPtrLow=SetFilePointer(hFile,lDistLow,&lDistHigh,FILE_BEGIN);

//Testforfailure

if(dwPtrLow==INVALID_SET_FILE_POINTER&&(dwError=GetLastError())!

=NO_ERROR)

{

//处理错误

//...

}//Endoferrorhandler

在Win32中没有提供得到文件当前指针位置的函数,但通过SetFilePointer也可以确定文件指针当前的位置。

在MSDN中提供了两个宏来得到当前文件的指针位置:

//对32位长度的文件

#defineGetFilePointer(hFile)SetFilePointer(hFile,0,NULL,FILE_CURRENT)

//对超过32位长度的文件

#defineGetVLFilePointer(hFile,lpPositionHigh)\

(*lpPositionHigh=0,\

SetFilePointer(hFile,0,lpPositionHigh,FILE_CURRENT))

对了可以通过SetFilePointer来得到文件长度,方法就是从文件位结束处移动0字节,返回值就是文件的长度。

HANDLEhFile=CreateFile(...);//打开文件进行读

DWORDdwLen;

dwLen=SetFilePointer(hFile,0,NULL,FILE_END);

CloseHandle(hFile);

当然Win32中也提供了专门的函数来得到文件的大小

BOOLGetFileSizeEx(

HANDLEhFile,//handletofile

PLARGE_INTEGERlpFileSize//filesize

);

typedefunion_LARGE_INTEGER{

struct{

DWORDLowPart;

LONGHighPart;

};

LONGLONGQuadPart;

}LARGE_INTEGER,*PLARGE_INTEGER;

其中lpFileSize是一个联合数据,用来表明文件的大小。

文件的异步读写主要是用在大文件的读写上,当使用异步读写时,ReadFile和WriteFile会马上返回,并在读写完成时通知应用程序。

要使用异步功能首先需要在打开文件时指定FILE_FLAG_OVERLAPPED作为标记(dwFlagsAndAttributes),在读写文件时可以使用ReadFile/WriteFile或者ReadFileEx/WriteFileEx来进行读写,当调用不同的函数时读写完成后通知应用程序的方法有所不同的,。

下面分别介绍这两种方法:

第一种方法,利用ReadFile/WriteFile,这对函数使用事件信号来进行读写完成的通知,由于磁盘读写是一个比较耗费时间的操作,而且现在的磁盘子系统可以在磁盘读写时脱离CPU而单独进行,例如使用DMA方式,所以在磁盘读写时可以进行其他一些操作以充分利用CPU。

关于事件信号相关内容请参考4.4节进程/线程间同步中事件部分内容。

并且在文件读写时提供OVERLAPPED数据。

结构定义如下:

typedefstruct_OVERLAPPED{

ULONG_PTRInternal;//系统使用

ULONG_PTRInternalHigh;//系统使用

DWORDOffset;//文件读或写的开始位置低32位,对于命名管道和其他通信设备必须设置为0

DWORDOffsetHigh;//文件读或写的开始位置高32位,对于命名管道和其他通信设备必须设置为0

HANDLEhEvent;//事件量,当操作完成时,这个时间会变为有信号状态

}OVERLAPPED;

//下面的代码演示了文件异步读取

//并且比较了同步和异步之间的性能差异

voidDoDataDeal(BYTE*pbData,intiLen)

{//对字节进行操作

Sleep(3*1000);//假设每次计算需要2秒钟

}

//下面是使用异步读的示范代码,假设c:

\temp\large_file.dat文件有130MB大小()

//每次读入10MB字节,并且对文件中每个字节进行操作,由于可以使用异步操作所以可以在下一次读入数据的同时进行计算

voidReadM1(void)

{

HANDLEhFile=CreateFile("c:

\\temp\\large_file.dat",GENERIC_READ,0,

NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED|FILE_ATTRIBUTE_NORMAL,NULL);

if(INVALID_HANDLE_VALUE!

=hFile)

{

HANDLEhEvent=CreateEvent(NULL,FALSE,FALSE,"read_event");

BYTE*pbRead=newBYTE[1024*1024*10];//10MB字节

BYTE*pbBuf=newBYTE[1024*1024*10];

DWORDdwRead,dwCount=0;

OVERLAPPEDoverlap;

overlap.Offset=0;

overlap.OffsetHigh=0;

overlap.hEvent=hEvent;

DWORDdwBegin=GetTickCount();//记录开始时间

ReadFile(hFile,pbRead,1024*1024*10,&dwRead,&overlap);

{//开始计算

for(inti=1;i<13;i++)

{

printf("M1i=%d\n",i);

WaitForSingleObject(hEvent,INFINITE);//等待上一次完成

memcpy(pbBuf,pbRead,1024*1024*10);

overlap.Offset=i*(1024*1024*10);

overlap.OffsetHigh=0;

overlap.hEvent=hEvent;

ReadFile(hFile,pbRead,1024*1024*10,&dwRead,&overlap);

//在文件进行读的同时进行计算

DoDataDeal(pbBuf,1024*1024*10);

}

WaitForSingleObject(hEvent,INFINITE);//等待最后一次完成

memcpy(pbBuf,pbRead,1024*1024*10);

//数据处理

DoDataDeal(pbBuf,1024*1024*10);

}//结束计算

printf("耗时%d\n",GetTickCount()-dwBegin);

//操作完成

CloseHandle(hEvent);

CloseHandle(hFile);

deletepbRead;

deletepbBuf;

}

}

//下面是上面功能的文件同步读版本

voidReadM2(void)

{

HANDLEhFile=CreateFile("c:

\\temp\\large_file.dat",GENERIC_READ,0,

NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

if(INVALID_HANDLE_VALUE!

=hFile)

{

DWORDdwRead,dwCount=0;

BYTE*pbRead=newBYTE[1024*1024*10];//10MB字节

BYTE*pbBuf=newBYTE[1024*1024*10];//10MB字节

DWORDdwBegin=GetTickCount();//记录开始时间

for(inti=0;i<13;i++)

{

printf("M2i=%d\n",i);

if(!

ReadFile(hFile,pbRead,1024*1024*10,&dwRead,NULL))

{

printf("errorread");

break;

}

memcpy(pbBuf,pbRead,1024*1024*10);

//计算

DoDataDeal(pbBuf,1024*1024*10);

}

printf("耗时%d\n",GetTickCount()-dwBegin);

//操作完成

CloseHandle(hFile);

deletepbRead;

deletepbBuf;

}

}

在文件的异步读写中,如果ReadFile/WriteFile返回FALSE,则需要通过LastError来进一步确认是否发生错误,例如下面的错误检测代码:

bResult=ReadFile(hFile,&inBuffer,nBytesToRead,&nBytesRead,

&gOverlapped);

if(!

bResult)

switch(dwError=GetLastError())

{

case

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 高中教育

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1