簡而言之,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);