ReadFile() WIN API

       ReadFile函数从文件指针指定的位置读取数据。读操作完成后,文件指针将根据实际读出的数据自动进行调整,除非文件句柄是以OVERLAPPED属性值打开的。如果是以OVERLAPPED打开的I/O,应用程序就需要自己手动调整文件指针。
      这个函数被设计成兼有同步和异步操作。ReadFileEx函数则设计成只支持异步操作,异步操作允许应用程序在读文件期间可以同时进行其他的操作。
    函数原型:
BOOL ReadFile(
HANDLE hFile,                // handle to file
LPVOID lpBuffer,             // data buffer
DWORD nNumberOfBytesToRead, // number of bytes to read
LPDWORD lpNumberOfBytesRead, // number of bytes read
LPOVERLAPPED lpOverlapped    // overlapped buffer
);

【Parameters】
1、hFile
    文件句柄(必须具有GENERIC_READ访问权限)。
    在Windows NT/2000/XP平台上:对于异步读操作,hFile可以是由CreateFile函数以FILE_FLAG_OVERLAPPED方式打开的任何句柄,或者一个由socket或accept函数返回的socket句柄。
    在Windows 95/98/Me平台上:对于邮槽、命名管道和磁盘文件不能使用异步读操作。 
2、lpBuffer
    用来接收从文件中读出的数据的缓冲区指针。
3、nNumberOfBytesToRead
    指明要读的字节总数。
4、lpNumberOfBytesRead
      一个变量指针,用来存储实际传输的字节总数。ReadFile在做所有事情(包括错误检查)之前,先将这个值赋为0。当ReadFile从一个命名管道上返回TRUE时这个参数为0,说明消息管道另一端调用WriteFile时设置的nNumberOfBytesToWrite 参数为0。
     在Windows NT/2000/XP平台上:如果lpOverlapped 为NULL,则lpNumberOfBytesRead不能为NULL。如果lpOverlapped 不是NULL,lpNumberOfBytesRead可以设为NULL。如果是一个overlapped形式的读操作,我们可以动用GetOverlappedResult函数来获得传输的实际字节数。如果hFile关联的是一个完成端口(I/O completion port),那么可以调GetQueuedCompletionStatus函数来获得传输的实际字节数。
     如果完成端口(I/O completion port)被占用,而你用的是一个用于释放内存的回调例程,对于lpOverlapped参数指向的OVERLAPPED结构体来说,为这个参数指定NULL可以避免重新分配内存时发生内存泄漏。内存泄漏会导致返回这个参数值时是一个非法值。
      Windows 95/98/Me平台上:这个参数不允许为NULL。
5、lpOverlapped
        一个指向OVERLAPPED结构体的指针。如果hFile是以FILE_FLAG_OVERLAPPED方式获得的句柄,这个结构是必须的,不能为NULL。(否则函数会在错误的时刻报告读操作已经完成了)。这时,读操作在由OVERLAPPED中Offset成员指定的偏移地址开始读,并且在实际完成读操作之前就返回了。在这种情况下,ReadFile返回FALSE,GerLastError报告从错误类型是ERROR_IO_PENDING。这允许调用进程继续其他工作直到读操作完成。OVERLAPPED结构中的事件将会在读操作完成时被使能。
    如果hFile不是以FILE_FLAG_OVERLAPPED方式获得的句柄,并且lpOverlapped为NULL,读操作就从当前文件的开始位置读起,直到读操作完成ReadFile函数才能返回。
    在Windows NT/2000/XP平台上:如果hFile不是以FILE_FLAG_OVERLAPPED方式获得的句柄,并且lpOverlapped不为NULL,则读操作在由OVERLAPPED中Offset成员指定的偏移地址开始读,直到读操作完成ReadFile函数才能返回。
    在Windows 95/98/Me平台上:对于文件、磁盘、管道和邮槽的操作,这个参数必须为NULL。一个不为空的OVERLAPPED结构体指针将导致调用失败。Windows 95/98/Me平台只支持串行口和并行口的overlapped 读写。

【Return Values】
    有如下任一种情况发生都会导致函数返回:(1)在管道另一端的写操作完成后(2)请求的字节数传输完毕(3)发生错误。
    如果函数正确,返回非零。
    如果返回值是非零,但接收的字节数是0,那么可能是文件指针在读操作期间超出了文件的end位置。然而,如果文件以FILE_FLAG_OVERLAPPED方式打开,lpOverlapped 参数不为NULL,文件指针在读操作期间超出了文件的end位置,那么返回值肯定是FALSE,GetLastError返回的错误是ERROR_HANDLE_EOF。

【Remarks】
    如果文件的一部分被另一个进程锁定,而当前进程试图重复锁定,那将会失败。
    一个应用程序在读以FILE_FLAG_NO_BUFFERING方式打开的文件时要符合一定的条件。
(1)文件读的开始地址必须是扇区大小的整数倍。GetDiskFreeSpace函数可以取得扇区的大小。
(2)请求读的字节数也必须是扇区大小的整数倍。
(3)用于读写操作的Buffer地址必须按照扇区大小进行边界对齐。可以通过用VirtualAlloc 函数申请内存来做到。
    在读操作期间试图访问相应的输入缓冲区,会导致读入到缓冲区的数据损坏。读操作完成之前,应用程序不能对这段输入缓冲区做任何操作(包括读、写、重新分配内存,释放内存等)。
    ReadFile可以通过指向控制台输入对象的句柄将控制台的输入字符读出来。控制台的模式决定了ReadFile的具体行为。
    如果一个命名管道正在以消息模式被读取,并且下一条消息比nNumberOfBytesToRead参数指定的长度还大,那么ReadFile将返回FALSE并且GetLastError返回错误为ERROR_MORE_DATA。剩下没读完的消息可能会被随后的ReadFile或PeckNamedPipe函数读出。
    读取一个通信设备时,ReadFile的行为被当前的通信延时所支配,延时属性的设置和取得使用SetCommTimeouts和GetCommTimeouts函数。如果你设置延时属性失败,就会得到不可预知的结果。
    如果ReadFile试图读取一个buffer太小的邮槽,将会返回FALSE并且GetLastError返回错误为ERROR_INSUFFICIENT_BUFFER 。
    如果一个匿名的写管道句柄已经关闭,而ReadFile试图用响应的匿名权限读这个管道句柄,将返回FALSE并且
GetLastError返回错误为ERROR_BROKEN_PIPE。
    每当有太多的异步I/O请求得不到响应,ReadFile就会失败,并返回ERROR_INVALID_USER_BUFFER或ERROR_NOT_ENOUGH_MEMORY的错误。
    在同步和异步两种情况下,ReadFile中检测EOF(文件结尾边界)的代码是不同的。当一个同步读操作到达文件结尾时,ReadFile返回TRUE,并设置*lpNumberOfBytesRead 为0 。异步读操作会在开始调用的读操作中或者随后的其他异步操作中突然遇到文件结尾。(1)如果EOF在ReadFile期间被检测到,将会返回FALSE,且 GetLastError返回错误描述 ERROR_HANDLE_EOF。(2)如果EOF在随后的其他异步操作中被检测到,则类似GetOverlappedResult 等试图获取操作结果的函数返回FALSE,且 GetLastError返回错误描述ERROR_HANDLE_EOF。
    为了取消未响应的异步I/O操作,用CancelIo函数。这个函数只能取消由调用进程对特定句柄进行的操作。被取消的I/O操作将被描述为ERROR_OPERATION_ABORTED。
    如果你正试图从并不存在的软驱中读数据,系统会弹出消息框提示你重新操作。为了阻止系统的消息框,调用函数SetErrorMode,参数设置为SEM_NOOPENFILEERRORBOX。

你可能感兴趣的:(C语言学习)