You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

重叠同步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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 09:22:14