简而言之,Overlapped IO 即异步 IO, 用于并发读写数据
一、Win32 的文件操作函数
HANDLE CreateFile(
LPCTSTR lpFileName, // 指向文件名称
DWORD dwDesiredAccess, // 存取模式(读或写)
DWORD dwShareMode, // 共享模式
LPSECURITY_ATTRIBUTES lpSecurity_attributes, // 安全属性
DWORD dwCreattionDisposition, // 如何产生
DWORD dwFlagsAndAttributes, // 文件属性
HANDLE hTemplateFile // 一个文件属性,将拥有全部文件属性拷贝
)
CreateFile 可以打开各种资源,而非仅仅文件, 包括:
* 文件
* 串行口,并行口
* Named Pipe
* Console
其参数 dwFlagsAndAttributes 是使用 Overlapped IO 的关键
Overlapped IO 的基本形式是以 ReadFile() 和 WriteFile() 来完成的, 二者原型如下:
BOOL ReadFile(
HANDLE hFile, // 欲读取的文件
LPVOID lpBuffer, // 接收缓冲
DWORD nNumberOfBytesToRead, // 读取字节数
LPDWORD lpNumberOfBytesToRead, // 实际读取的字节数
LPOVERLAPPED lpOverlapped // 指向一个 overlapped info
);
BOOL WriteFile(
HANDLE hFile, // 要写的文件
LPVOID lpBuffer, // 数据缓冲区
DWORD nNumberOfBytesToWrite, // 打算写入的字节数
LPVOID lpNumberOfBytesWritten, // 实际写入的字节数
LPOVERLAPPED lpOverlapped // 指向一个 overlapped info
);
如果 CreateFile 的第 6 个参数 dwFlagsAndAttributes 被指定为 FILE_FLAG_OVERLAPPED, 则 ReadFile() 和 WriteFile()
的参数需提供一个指向 OVERLAPPED 的结构指针
二、OVERLAPPED 结构
typedef struct _OVERLAPPED {
DWORD Internal;
DWORD InternalHigh;
DWORD Offset; // 文件被读或被写的偏移
DWORD OffsetHigh;
HANDLE hEvent;
} OVERLAPPED
三、Overlapped 如何运作
以最简单的 Overlapped IO 为例
(1) 你在 CreateFile() 时指定 FILE_FLAG_OVERLAPPED 告诉 Win32 你要使用 Overlapped IO 特性
(2) 调用 ReadFile(), 并传递一个指向 Overlapped 的指针
(3) Win32 会在后台处理你的请求,你的程序可以继续做其它事情
(4) 如果你要等待 Overlapped IO 的结果,请用 WaitForMultipleObject() 等待你读写文件的 handle, 因为文件 handle 是一个核心对象, 一旦操作完成就被激发。当你完成其它操作之后,可调用 GetOverlappedResult() 确定结果如何。
1
2 HANDLE hFile;
3 OVERLAPPED overlap;
4
5 // Open the file for overlapped reads
6 hFile = CreateFile( szPath,
7 GENERIC_READ,
8 FILE_SHARE_READ|FILE_SHARE_WRITE,
9 NULL,
10 OPEN_EXISTING,
11 FILE_FLAG_OVERLAPPED,
12 NULL
13 );
14
15 if (hFile == INVALID_HANDLE_VALUE)
16 return -1;
17
18 // Initialize the OVERLAPPED structure
19 memset(&overlap, 0, sizeof(overlap));
20 overlap.Offset = 1500;
21
22 // Request the data
23 rc = ReadFile(
24 hFile,
25 buf,
26 READ_SIZE,
27 &numread,
28 &overlap
29 );
30
31 // Was the operation queued?
32 if (rc)
33 {
34 // The data was read successfully
35 }
36 else
37 {
38 if (GetLastError() == ERROR_IO_PENDING)
39 {
40 // We could do something else for awhile here
41 WaitForSingleObject(hFile, INFINITE);
42
43 rc = GetOverlappedResult(
44 hFile,
45 &overlap,
46 &numread,
47 FALSE
48 );
49 }
50 else
51 {
52 // Something went wrong
53 printf("Error reading file\n");
54 }
55 }
56
57 CloseHandle(hFile);