overlapped编程
int main(void) { BOOL fOk = FALSE; HANDLE hFileSrc = CreateFile(_T("test.txt"),GENERIC_READ,FILE_SHARE_READ,NULL, OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL); HANDLE hFileDest = CreateFile(_T("cpy_test.txt"),GENERIC_WRITE,0,NULL,CREATE_ALWAYS, FILE_FLAG_OVERLAPPED,NULL); if (hFileSrc == INVALID_HANDLE_VALUE || hFileDest == INVALID_HANDLE_VALUE) { cout<<GetLastError()<<endl; system("pause"); return 1; } BOOL ret = FALSE; char str[1024] = {0}; DWORD dwNumberRead = 0; OVERLAPPED ov = {0}; ov.hEvent = NULL; ov.Offset = 0; ov.OffsetHigh = 0; while (true) { ret = ReadFile(hFileSrc,str,1023,&dwNumberRead,&ov); if (ret == FALSE) { if (GetLastError() == ERROR_IO_PENDING) { GetOverlappedResult(hFileSrc,&ov,&dwNumberRead,true); } else { cout<<GetLastError()<<endl; break; } } if (ov.InternalHigh == 0) { break; } str[ov.InternalHigh] = 0; cout<<str<<endl; ov.Offset += ov.InternalHigh; memset(str,0,sizeof(str)); } }
代码基本都是在读取的时候立即返回,而不是类似阻塞IO那样,一直到读完才返回,基本原理也就是把这个把IO放进队列里面,如果请求只是放进队列里面而没有处理,getlasterror返回的是ERROR_IP_PENDING,这个时候GetOverlappedResult是等待读完再继续,也可以WaitSingleObejct要读取的文件或者overlapped里面的hevent来等待读完..
刚写完这段代码就有点奇怪,既然要等待他读完才能继续执行,为什么还要用异步,用同步不也可以??后来想了下,这样做的好处就是可以让原本等待在IO操作完成的时间中做其他事情,然后到一定的地方在等待完成,如果使用非阻塞IO,在IO操作完成操作后需要调用一段函数,而这段函数又与IO操作无关,这样无缘无故浪费了中间一段时间,还不如在IO操作前做些其他的事情....最近工作用到的读串口也是这样,虽然也是在调用ReadFile后立即等待操作完成,但是如果哪天需要在中间加入 一些操作,那修改起来就很麻烦...
还有一个比较2B的时候,我在调用CreateFile的时候使用了FILE_FLAG_NO_BUFFERING这个标志,结果读的时候总是错误,说是无效参数,后来发现是在CreateFile的时候指定了FILE_FLAG_NO_BUFFERING
MSDN是这样说的:
The file or device is being opened with no system caching for data reads and writes. This flag does not affect hard disk caching or memory mapped files.
There are strict requirements for successfully working with files opened with CreateFile using the FILE_FLAG_NO_BUFFERING flag, for details see File Buffering.
windows核心编程里面则说指定了这个标志后读写必须使用64的倍数....
需要注意的是,传入的是overlapped的地址,所以在overpaeed作用域过后,如果IO操作还没完成,则会发生未知错误
如下代码
void ReadData(HANDLE hFile) { OVERLAPPED ov = {0}; ov.hEvent = NULL; BYTE b[100]; ReadFile(hFile,b,100,&ov); }