深入解析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操作,特别是在需要高性能和灵活控制的系统级开发中。
热门推荐
你应该用USB还是或耳机插孔连接你的电脑耳机?这里有详细解释
滨海盐沼的真相:美国太平洋沿岸湿地损失严重,超过60%
阳台盆栽月季品种推荐:8个适合新手的易养品种
家里阳台种月季花好吗?解锁阳台园艺新时尚
中国古代刑法概述与演变
十代思域底盘异响问题解析与解决方案
羽毛球比赛计分表怎么填,羽毛球比赛怎么计分表怎么填写
UVM的基本概念和架构
牙套橡胶变黄怎么办?实用清洁技巧全攻略
让杨树猛长的技巧
单口相声和脱口秀哪不一样?懂喜剧的都知道里面的门道有多深……
单口相声和脱口秀到底哪不一样?
多地发布新一轮生育意愿调查报告:还有哪些痛点?现行政策奏效吗?
偏差与方差的基本概念
怎样在银行办理个人储蓄账户的资金监控设置?
走进人文世界,摄影镜头选“优”实用手册!
被起诉后会有案底吗?对家人和生活的影响有哪些?
银行ATM机跨行取款手续费的调整与客户体验
怎样正确使用薛斯通道?使用薛斯通道时需注意哪些问题?
自考答题指南:答题卡使用与注意事项全解析
刀郎的《罗刹海市》,到底暗讽了什么?
金牛座的故事:神秘的星座背後的神话与性格解析
围绝经期怎么调理需要调理吗
面黄褐斑不用怕,让你肌肤焕新
如何正确选择适合车辆的火花塞型号?不同型号的火花塞有何差异?
如何通过改善睡眠环境解决睡觉老出汗问题?
个体工商户需要名字吗
个体工商户名称登记的法律规范与实务指南
温州医科大学附属第一医院陈钢团队揭示肠道益生菌-粪肠球菌增敏肝癌靶向治疗新机制
AI助力医院智慧化转型:温州医科大学附属第一医院加快落地实践