深入解析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操作,特别是在需要高性能和灵活控制的系统级开发中。
热门推荐
牛排知识全科普!这些你都知道吗?
让猫咪轻松服药:15个实用技巧全攻略
这10个提示词技巧太强了,用过的人都说真香!
河北石家庄荣国府景区:明清风华,红楼遗韵
长安为何失去“首都”地位?从辉煌巅峰到落寞地方城的真相
留学美国需要准备什么样的笔记本电脑
单目线激光标定一(相机标定)
英雄阵亡后,使用不同的方式复活,差异不仅只是魔法值
深度解析:全球股市表现的五大经济驱动因素
轻松打开和编辑.md文件的多种方法与技巧介绍
门窗安装全攻略:五大步骤详解
因呕吐导致发烧怎么办?这份实用指南请收好
田氏如何顺利取代姜齐?一文带你全面了解“田氏代齐”的历史过程
比"恋爱脑"更可怕的"性缘脑"是个什么东西?如何判断自己有没有"中招"?
眼下细纹怎么治疗
智能农业:作物害虫识别App的功能与优势
七次课掌握 Photoshop:调整与混合
美食三步法:滑蛋虾仁速成的极致享受
罗氏宗祠知多少
夏季油冬季干,你的肤质到底属于哪一类
“门罗效应”是什么?给炸药加个金属罩,竟然能直接影响战争进程
曹操是怎么看出来刘备是英雄的?看史书记载,有3个原因
如何用数据库做统计分析
星光夜市人气足 “烟火气”点亮“夜经济”
销售工程师和销售区别
几月份种黄瓜最合适?从播种到采收的完整种植指南
如何在Android上从5GHzWiFi切换到2.4GHzWiFi并避免出现问题
原神零氪党最强阵容推荐:雷国队、国家队和砂糖武装队
养龟秘籍:5 大“不死龟种”推荐,轻松饲养无烦恼
《庆余年》9大金句影响人生抉择!各角色都有精辟对白贯穿全剧