深入解析Windows API中的ReadFile函数
创作时间:
作者:
@小白创作中心
深入解析Windows API中的ReadFile函数
引用
CSDN
等
7
来源
1.
https://blog.csdn.net/weixin_34405557/article/details/85563077
2.
https://www.easefilter.com/kb/fileapi-readfile.htm
3.
https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile#parameters
4.
https://learn.microsoft.com/zh-cn/windows/win32/fileio/testing-for-the-end-of-a-file
5.
https://learn.microsoft.com/zh-tw/windows/win32/api/fileapi/nf-fileapi-readfile
6.
https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile
7.
https://www.cnblogs.com/liujx2019/p/11691495.html
在Windows操作系统中,ReadFile函数是API的重要组成部分,用于从文件或设备(如串口、硬盘)中读取数据。它是同步和异步I/O操作的基础,广泛应用于文件读取、串口通信、网络通信以及传感器数据读取等多种场景。本文将深入解析ReadFile函数的参数、返回值及其实际应用示例,帮助开发者更好地理解和使用这一关键功能。
01
函数基础介绍
ReadFile函数是Windows API中用于读取文件或I/O设备数据的核心函数。其主要功能是从指定的文件或设备中读取数据到应用程序的缓冲区中。该函数支持同步和异步操作模式,适用于各种I/O设备,包括文件、串口、网络套接字等。
与其他读取函数(如fread、ReadFileEx)相比,ReadFile具有以下特点:
- 通用性:支持多种I/O设备,不仅限于文件
- 灵活性:同时支持同步和异步操作
- 系统级:直接与操作系统内核交互,性能更优
02
函数原型与参数详解
BOOL ReadFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped
);
参数名称 | 类型 | 描述 |
|---|---|---|
hFile | HANDLE | 要读取的设备句柄(如文件、串口等) |
lpBuffer | LPVOID | 存储读取数据的缓冲区指针 |
nNumberOfBytesToRead | DWORD | 请求读取的最大字节数 |
lpNumberOfBytesRead | LPDWORD | 指向变量的指针,接收实际读取的字节数 |
lpOverlapped | LPOVERLAPPED | 异步操作时需提供的OVERLAPPED结构体指针 |
- hFile:要读取的设备句柄,必须具有读取权限。对于异步操作,句柄需要通过
CreateFile函数使用FILE_FLAG_OVERLAPPED标志创建,或者是一个由socket或accept函数返回的套接字句柄。 - lpBuffer:指向缓冲区的指针,用于存储读取的数据。在读取操作完成前,不应使用此缓冲区。
- nNumberOfBytesToRead:请求读取的最大字节数。
- lpNumberOfBytesRead:指向一个变量的指针,用于接收实际读取的字节数。在同步模式下必须提供,异步模式下可以为NULL。
- lpOverlapped:指向
OVERLAPPED结构体的指针。如果hFile是使用FILE_FLAG_OVERLAPPED打开的,则必须提供有效的OVERLAPPED结构体,否则可以为NULL。
03
返回值与错误处理
ReadFile函数的返回值是一个布尔值:
- 成功时返回非零值(
TRUE) - 失败时返回零(
FALSE)
当函数返回FALSE时,可以通过GetLastError()函数获取具体的错误码。常见的错误码包括:
ERROR_IO_PENDING:异步操作尚未完成ERROR_HANDLE_EOF:同步读取到达文件末尾ERROR_INVALID_HANDLE:无效的设备句柄ERROR_ACCESS_DENIED:没有读取权限
特别需要注意的是,ERROR_IO_PENDING并不表示错误,而是表明异步操作正在等待完成。在这种情况下,可以通过GetOverlappedResult函数检查操作的最终状态。
04
使用示例
同步读取示例
#include <windows.h>
#include <stdio.h>
int main() {
HANDLE hFile = CreateFile("example.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
printf("Failed to open file.\n");
return -1;
}
char buffer[1024];
DWORD bytesRead;
while (ReadFile(hFile, buffer, sizeof(buffer), &bytesRead, NULL)) {
if (bytesRead > 0) {
// 处理读取的数据
printf("%.*s", (int)bytesRead, buffer);
} else {
break; // 文件结束
}
}
DWORD error = GetLastError();
if (error != ERROR_SUCCESS && error != ERROR_HANDLE_EOF) {
printf("Error reading file: %lu\n", error);
}
CloseHandle(hFile);
return 0;
}
异步读取示例
#include <windows.h>
#include <stdio.h>
void GoDoSomethingElse() {
printf("Inside GoDoSomethingElse()\n");
}
DWORD AsyncReadFile(HANDLE hEvent, HANDLE hFile) {
char inBuffer[64];
DWORD nBytesToRead = 64;
DWORD dwBytesRead = 0;
OVERLAPPED stOverlapped = {0};
DWORD dwError = 0;
BOOL bResult = FALSE;
BOOL bContinue = TRUE;
stOverlapped.hEvent = hEvent;
while (bContinue) {
bResult = ReadFile(hFile, inBuffer, nBytesToRead, &dwBytesRead, &stOverlapped);
dwError = GetLastError();
if (!bResult) {
switch (dwError) {
case ERROR_HANDLE_EOF:
printf("\nReadFile returned FALSE and EOF condition, async EOF not triggered.\n");
break;
case ERROR_IO_PENDING:
while (TRUE) {
GoDoSomethingElse();
bResult = GetOverlappedResult(hFile, &stOverlapped, &dwBytesRead, FALSE);
if (!bResult) {
dwError = GetLastError();
if (dwError == ERROR_HANDLE_EOF) {
printf("GetOverlappedResult found EOF\n");
break;
} else if (dwError == ERROR_IO_INCOMPLETE) {
continue;
} else {
printf("Error in GetOverlappedResult: %lu\n", dwError);
break;
}
} else {
// 处理读取的数据
printf("%.*s", (int)dwBytesRead, inBuffer);
break;
}
}
break;
default:
printf("Error in ReadFile: %lu\n", dwError);
break;
}
} else {
// 处理读取的数据
printf("%.*s", (int)dwBytesRead, inBuffer);
}
}
return dwBytesRead;
}
05
注意事项
- 缓冲区管理:确保提供的缓冲区在读取操作完成前保持有效,不要在读取过程中释放或重用缓冲区。
- 异步操作的线程安全:在多线程环境中使用异步读取时,需要确保
OVERLAPPED结构体的线程安全性。 - 错误处理:始终检查
ReadFile的返回值,并在失败时调用GetLastError()获取详细错误信息。 - 文件末尾处理:在同步读取中,当
lpNumberOfBytesRead为0且GetLastError()返回ERROR_HANDLE_EOF时,表示已到达文件末尾。
06
对比分析
与ReadFileEx相比,ReadFile的主要区别在于:
ReadFile同时支持同步和异步操作,而ReadFileEx仅支持异步操作。ReadFile的异步操作需要手动检查完成状态,而ReadFileEx可以指定一个完成例程,在操作完成后自动调用。
总结来说,ReadFile函数是Windows API中处理文件和设备读取的核心工具。通过理解其参数、返回值和使用场景,开发者可以更有效地进行I/O操作,特别是在需要高性能和灵活控制的系统级开发中。
热门推荐
传统与现代交融,创新呈现中国意境
长沙三大网红景点全攻略:岳麓山、橘子洲、杜甫江阁
昭和奥特曼系列人间体命名源流初探
阿根廷新总统的家庭密码:从犹太血统到权力巅峰
做入境游,从“新手村”上海出发
海南省文昌市旅游指南:一文掌握文昌精华景点与必游之地
灵蛇献瑞:辽宁省博物馆里的蛇年文化探秘
赵保乐:从相声演员到春晚全能王
2025春晚新动向:任鲁豫、撒贝宁搭档“外卖诗人”王计兵
朱军:21年春晚主持生涯背后的坚守与转型
货车监控器布线技巧大揭秘!
蒋勤勤亚洲电影大奖背后的故事
西安永兴坊:一坊藏千秋,一步一故事,全国首个非遗美食文化街区
洞头区跨年烟花夜,元旦狂欢不容错过!
洞头一日游:打卡最美海岛景点
川青铁路正式通达黄龙、九寨沟,坐着高铁游川西,那美景是谁打翻的调色板
《食物语》玩家必看:西凤酒最佳搭配攻略
压岁钱不超过20?年轻人又开始“整顿”春节了
朱军《艺术人生》:用对话点亮艺术,用真诚温暖人心
朱军无缘2025春晚,但他的艺术生涯和对春晚的贡献将永远被观众铭记
朱军复出首秀惊艳全场,春晚舞台能否再续辉煌?
虾苗价格持续上涨,养殖户如何挑选优质虾苗?
小龙虾养殖塘肥水要怎么做?虾塘肥水有妙招,其实肥水很简单!
48岁的蒋勤勤,彻底告别了“琼瑶女郎”
青梅竹马,文学与文化中的永恒主题
小户型风水布局,这些雷区你踩过吗?
小夫妻的装修秘籍:小两居也能变豪宅!
冬日探秘石竹山:道教文化之旅
探秘福清石竹山:中华梦乡的千年祈梦文化
秋日打卡:赣州最美摄影点推荐