ReadFile

基本概念

ReadFileWindows API(Win32 API) 中的核心文件I/O函数,用于从已打开的文件、设备(如串口、管道、磁盘分区)或I/O对象中读取数据,是Windows系统下底层数据读取的基础接口。它支持 同步读取异步读取两种模式,适用于几乎所有Windows可访问的I/O设备。
ReadFile 的返回值为BOOL类型,仅表示 函数调用是否成功启动/完成,不直接代表 “是否读取到数据”:
返回 TRUE
同步模式:读取操作已完成(可能读取到0字节,如文件末尾);
异步模式:读取操作已成功提交(需后续通过WaitForSingleObjectGetOverlappedResult等确认完成)。
返回FALSE:
操作失败,需通过GetLastError()函数获取具体错误码,常见错误包括:
ERROR_HANDLE_EOF:已到达文件末尾(EOF),无更多数据可读;
ERROR_ACCESS_DENIED:文件句柄无读权限;
ERROR_IO_PENDING:异步操作尚未完成(非 “错误”,需等待);
ERROR_INVALID_HANDLE:传入的hFile是无效句柄。

语法

1
2
3
4
5
6
7
BOOL ReadFile(
[in] HANDLE hFile, // 已打开文件的句柄
[out] LPVOID lpBuffer, // 接收数据的内存缓冲区指针
[in] DWORD nNumberOfBytesToRead, // 期望读取的字节数
[out, optional] LPDWORD lpNumberOfBytesRead, // 实际读取的字节数
[in, out, optional] LPOVERLAPPED lpOverlapped // 用于异步操作的结构体指针
);

LPVOID定义:

1
2
3
4
typedef void far            *LPVOID;

void far * :表示 “可指向任意段内存的通用指针”;
总结:可指向任意类型数据的远指针.

LPDWORD定义:

1
2
3
4
typedef DWORD far           *LPDWORD;

DWORD :32 位无符号整数(等价于 unsigned long);
总结:指向 DWORD 类型的(远)指针.

LPOVERLAPPED定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
typedef struct _OVERLAPPED {
ULONG_PTR Internal;
ULONG_PTR InternalHigh;
union {
struct {
DWORD Offset;
DWORD OffsetHigh;
} DUMMYSTRUCTNAME;
PVOID Pointer;
} DUMMYUNIONNAME;

HANDLE hEvent;
} OVERLAPPED, *LPOVERLAPPED;

ULONG_PTR Internal :系统内部使用的字段,通常存储异步操作的状态信息(如错误码);
ULONG_PTR InternalHigh :同样为系统内部使用,通常存储异步操作的结果(如实际传输的字节数);
联合体 DUMMYUNIONNAME :
子结构体 DUMMYSTRUCTNAME :包含 Offset(低 32 位)和 OffsetHigh(高 32 位)两个 DWORD 成员,合起来表示 64 位的文件偏移量,
用于文件 / 设备的异步读写操作,指定从文件的哪个位置开始读写(适用于支持随机访问的设备,如文件);
PVOID Pointer :一个通用指针(void*),用于传递用户自定义的上下文数据;
HANDLE hEvent :一个事件句柄(HANDLE),用于异步操作完成时的通知。
总结:OVERLAPPED 结构体是 Windows 重叠 I/O 模型的基础,用于在调用异步 API(如 ReadFileEx、WriteFileEx、WSARecv 等)时传递必要的上下文信息;
LPOVERLAPPED是指向该结构体的指针类型。

简单示例(同步读取)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <windows.h>
#include <stdio.h>

int main() {
// 1. 打开文件(获取读权限句柄)
HANDLE hFile = CreateFile(
L"test.txt", // 目标文件路径(Unicode)
GENERIC_READ, // 读权限
FILE_SHARE_READ, // 共享读(其他进程可同时读)
NULL, // 默认安全属性
OPEN_EXISTING, // 仅打开已存在的文件
FILE_ATTRIBUTE_NORMAL, // 普通文件属性(同步读取)
NULL // 无模板文件
);
if (hFile == INVALID_HANDLE_VALUE) {
printf("CreateFile failed! Error: %lu\n", GetLastError());
return 1;
}

// 2. 分配缓冲区(假设读取1024字节)
char buffer[1024] = {0};
DWORD bytesToRead = 1024;
DWORD bytesRead = 0;

// 3. 调用 ReadFile 同步读取
BOOL success = ReadFile(
hFile, // 已打开的句柄
buffer, // 接收数据的缓冲区
bytesToRead, // 期望读取1024字节
&bytesRead, // 实际读取的字节数
NULL // 同步读取,设为NULL
);

// 4. 处理结果
if (success) {
if (bytesRead == 0) {
printf("已到达文件末尾(EOF)\n");
} else {
printf("读取成功!实际读取 %lu 字节,内容:\n%s\n", bytesRead, buffer);
}
} else {
printf("ReadFile failed! Error: %lu\n", GetLastError());
}

// 5. 关闭句柄(必须释放资源)
CloseHandle(hFile);
return 0;
}

WriteFile

基本概念

WriteFileWindows API(Win32 API)用于向文件或其他可写设备(如管道、串口、磁盘等)写入数据的核心函数,支持同步和异步(重叠I/O)两种操作模式。它是文件I/O操作的基础API之一,它是ReadFile的对应函数,共同构成了文件I/O的基础。
ReadFile 的返回值为BOOL类型,
成功时返回 TRUE(非零)。
失败时返回 FALSE(0),可通过GetLastError获取具体错误码(如ERROR_ACCESS_DENIED表示无权限,ERROR_DISK_FULL表示磁盘满)。
特殊情况:异步操作时,若函数返回FALSEGetLastError返回ERROR_IO_PENDING,表示操作已成功发起并在后台进行,并非真正失败。

语法

1
2
3
4
5
6
7
BOOL WriteFile(
[in] HANDLE hFile, // 文件/设备句柄
[in] LPCVOID lpBuffer, // 指向要写入数据的缓冲区的指针
[in] DWORD nNumberOfBytesToWrite, // 要写入的字节数
[out, optional] LPDWORD lpNumberOfBytesWritten, // 接收实际写入字节数的指针
[in, out, optional] LPOVERLAPPED lpOverlapped // 用于异步操作的结构体指针
);

参数的数据类型和ReadFie一样。

简单示例(同步写入)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <windows.h>
#include <stdio.h>

int main() {
// 打开文件(创建或覆盖,允许写入)
HANDLE hFile = CreateFileA(
"test.txt", // 文件名
GENERIC_WRITE, // 写入权限
0, // 不共享
NULL, // 默认安全属性
CREATE_ALWAYS, // 若存在则覆盖,否则创建
FILE_ATTRIBUTE_NORMAL,// 普通文件属性(同步模式)
NULL // 无模板
);

if (hFile == INVALID_HANDLE_VALUE) {
printf("打开文件失败,错误码: %d\n", GetLastError());
return 1;
}

// 待写入的数据
const char* data = "Hello, WriteFile!";
DWORD bytesToWrite = strlen(data);
DWORD bytesWritten;

// 同步写入
BOOL success = WriteFile(
hFile,
data,
bytesToWrite,
&bytesWritten,
NULL // 同步模式,lpOverlapped为NULL
);

if (success) {
printf("写入成功,实际写入 %d 字节\n", bytesWritten);
} else {
printf("写入失败,错误码: %d\n", GetLastError());
}

// 关闭文件句柄
CloseHandle(hFile);
return 0;
}