重叠同步ReadFile读取超文件大小未触发ERROR_HANDLE_EOF问题
同步文件句柄结合OVERLAPPED读取到EOF未触发ERROR_HANDLE_EOF的原因解析
场景重现
现有文件信息
existingfile.txt 大小为88字节,内容如下:
The First Order Derivative of X2 is 2x. The derivative of sin is cos. Math is the best
测试代码
main.cpp 实现逻辑:打开同步文件句柄、获取文件大小、从偏移15处读取1000字节并输出内容,代码如下:
#include <windows.h> #include <cstdio> int main(int, char**){ //Creating Synchronous File Handle HANDLE hFile = CreateFileW( L"existingfile.txt", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL ); if (hFile == INVALID_HANDLE_VALUE) { printf("ERROR IN OPENING FILE %lu\n", GetLastError()); return -1; } //Obtaining File Size { ULARGE_INTEGER FileSize; FileSize.LowPart = GetFileSize(hFile, &FileSize.HighPart); DWORD LastError = GetLastError(); if (FileSize.LowPart == INVALID_FILE_SIZE && LastError != NO_ERROR){ printf("FAILED TO OBTAIN FILE SIZE, ERROR %lu\n", LastError); return -1; } printf("FILE SIZE: %llu\n", FileSize.QuadPart); } //Reading To End Of the File { OVERLAPPED Overlapped = {}; Overlapped.Offset = 15; Overlapped.OffsetHigh = 0; constexpr DWORD NumBytesToRead = 1000; char BytesRead[NumBytesToRead + 1] = {0}; BOOL Successful = ReadFile(hFile, BytesRead, NumBytesToRead, NULL, &Overlapped); DWORD LastError = GetLastError(); if (!Successful){ if (LastError != ERROR_HANDLE_EOF){ printf("ERROR IN OVERLAPPED SYNCHRONOUS READ TO EOF, ERROR %lu\n", LastError); return -1; } puts("EOF ENCOUNTERED IN OVERLAPPED SYNCHRONOUS READ TO EOF"); } BytesRead[NumBytesToRead] = 0; printf("2: Information Read: '%s'\n", BytesRead); } CloseHandle(hFile); return 0; }
输出对比
- 实际输出:
FILE SIZE: 88 2: Information Read: ' Derivative of X2 is 2x. The derivative of sin is cos. Math is the best'
- 预期输出:
FILE SIZE: 88 EOF ENCOUNTERED IN OVERLAPPED SYNCHRONOUS READ TO EOF 2: Information Read: ' Derivative of X2 is 2x. The derivative of sin is cos. Math is the best'
核心原因
Windows API中ReadFile针对同步句柄+非空OVERLAPPED的返回规则明确:
- 只要读取操作成功获取到至少1字节数据,哪怕后续到达文件末尾,
ReadFile会返回TRUE,GetLastError()返回NO_ERROR,不会触发ERROR_HANDLE_EOF分支。 - 仅当读取起始位置已处于EOF(偏移量≥文件大小),或读取操作完全未获取到任何字节时,
ReadFile才会返回FALSE,且GetLastError()返回ERROR_HANDLE_EOF。
在当前场景中,文件总大小88字节,从偏移15处开始读取,实际可读取88-15=73字节,这部分数据被成功读取,因此ReadFile返回TRUE,不会触发EOF错误分支。
正确检测EOF的方式
因为使用了OVERLAPPED,无法通过ReadFile的第四个参数直接获取实际读取字节数,需调用GetOverlappedResult获取该值,再判断是否小于请求读取的字节数,以此确认是否到达EOF。修改后的读取分支示例:
BOOL Successful = ReadFile(hFile, BytesRead, NumBytesToRead, NULL, &Overlapped); DWORD BytesReadActual = 0; DWORD LastError = GetLastError(); if (!Successful){ if (LastError != ERROR_HANDLE_EOF){ printf("ERROR IN OVERLAPPED SYNCHRONOUS READ TO EOF, ERROR %lu\n", LastError); return -1; } puts("EOF ENCOUNTERED IN OVERLAPPED SYNCHRONOUS READ TO EOF"); } else { GetOverlappedResult(hFile, &Overlapped, &BytesReadActual, TRUE); if (BytesReadActual < NumBytesToRead) { puts("EOF ENCOUNTERED IN OVERLAPPED SYNCHRONOUS READ TO EOF"); } }
内容的提问来源于stack exchange,提问作者timmy george
相关产品推荐
相关产品推荐

