用IO完成端口实现文件异步读操作

IO完成端口是个比较复杂的内核对象,目前本人也是处于学习中,先写一个文件读写的例子,其中文件读用IO完成端口,文件写暂时用阻塞的方式,避免开始就难理解的局面。
下面直接上代码。

// FileOverlapped.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <Windows.h>


DWORD WINAPI ThreadFunc(LPVOID);


HANDLE hFileRead = INVALID_HANDLE_VALUE;
HANDLE hFileWrite = INVALID_HANDLE_VALUE;

#define LEN_READ_WRITE 1024
DWORD dwFileLen = 0;
DWORD dwFileAlreadyReadLen = 0;

typedef struct
{
    
    
	OVERLAPPED overlap;
	char buf[1024];
} cp_overlapped;

cp_overlapped *pCpOverLapped = NULL;

int main()
{
    
    
	hFileRead = CreateFile("D:\\video\\xingjichuanyue.rmvb", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL);
	if (hFileRead == INVALID_HANDLE_VALUE)
	{
    
    
		return -1;
	}

	hFileWrite = CreateFile("D:\\video\\xingjichuanyue_normal.rmvb", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFileWrite == INVALID_HANDLE_VALUE)
	{
    
    
		return -1;
	}
	dwFileLen = GetFileSize(hFileRead, NULL);

	pCpOverLapped = new cp_overlapped;
	pCpOverLapped->overlap.hEvent = NULL;
	pCpOverLapped->overlap.Offset = 0;
	pCpOverLapped->overlap.OffsetHigh = 0;

	HANDLE iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
	HANDLE iocp2 = CreateIoCompletionPort(hFileRead, iocp, 10001, 0);
	BOOL bRet = ReadFile(hFileRead, pCpOverLapped->buf, LEN_READ_WRITE, NULL, &pCpOverLapped->overlap);
	DWORD err = ::GetLastError();

	HANDLE hThread;
	DWORD  threadId;
	hThread = CreateThread(NULL, 0, ThreadFunc, (LPVOID)iocp, 0, &threadId); // 创建线程

	WaitForSingleObject(hThread, INFINITE);
    return 0;
}


DWORD WINAPI ThreadFunc(LPVOID p)
{
    
    
	HANDLE iocp = (HANDLE)p;
	DWORD dwReaded = 0;
	DWORD key = 0;
	cp_overlapped * s = 0;
	while (1)
	{
    
    
		dwReaded = 0;
		BOOL bRet = GetQueuedCompletionStatus(iocp, &dwReaded, &key, (LPOVERLAPPED*)&s, INFINITE);
		if (bRet)
		{
    
    
			bRet = WriteFile(hFileWrite, s->buf, dwReaded, NULL, NULL);
			if (dwReaded <= 0)
			{
    
    
				CloseHandle(hFileWrite);
				break;
			}
			dwFileAlreadyReadLen += dwReaded;
			if (dwFileAlreadyReadLen >= dwFileLen)
			{
    
    
				CloseHandle(hFileWrite);
				break;
			}
			pCpOverLapped->overlap.hEvent = NULL;
			pCpOverLapped->overlap.Offset += dwReaded;
			pCpOverLapped->overlap.OffsetHigh = 0;  
			bRet = ReadFile(hFileRead, pCpOverLapped->buf, LEN_READ_WRITE, NULL, &pCpOverLapped->overlap);
		}
	}
	return 0;
}

代码里面,线程函数里面有这么两句话,pCpOverLapped->overlap.Offset += dwReaded;
pCpOverLapped->overlap.OffsetHigh = 0; 这个是文件偏移量,告知操作系统,文件从什么位置开始读,这个必须设置,如果不设置,则每次读取的都是最开始的1024个字节。还有就是如果文件读完了,发起ReadFile请求时,GetQueuedCompletionStatus会阻塞,所以判断文件是否读完,需要事先获取文件的大小,这点与同步读不一样,同步读不需要获取文件大小。

猜你喜欢

转载自blog.csdn.net/tusong86/article/details/113775255