根据 MSDN,ReadFile
可以通过两种不同的方式读取数据:同步和异步。
我需要第二个。以下代码演示了 OVERLAPPED
的用法结构:
#include <windows.h>
#include <stdio.h>
#include <time.h>
void Read()
{
HANDLE hFile = CreateFileA("c:\\1.avi", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if ( hFile == INVALID_HANDLE_VALUE )
{
printf("Failed to open the file\n");
return;
}
int dataSize = 256 * 1024 * 1024;
char* data = (char*)malloc(dataSize);
memset(data, 0xFF, dataSize);
OVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(overlapped));
printf("reading: %d\n", time(NULL));
BOOL result = ReadFile(hFile, data, dataSize, NULL, &overlapped);
printf("sent: %d\n", time(NULL));
DWORD bytesRead;
result = GetOverlappedResult(hFile, &overlapped, &bytesRead, TRUE); // wait until completion - returns immediately
printf("done: %d\n", time(NULL));
CloseHandle(hFile);
}
int main()
{
Read();
}
在 Windows XP 上输出为:
阅读:1296651896
发送:1296651896
完成:1296651899
这意味着
ReadFile
没有阻塞并在同一秒立即返回,而读取过程持续了 3 秒。这是正常的异步读取。但是在 Windows 7 和 Windows 2008 上,我得到以下结果:
阅读:1296661205
发送:1296661209
完成:1296661209。
这是同步读取的一种行为。
MSDN 说异步
ReadFile
有时可以表现为同步(例如,当文件被压缩或加密时)。但是这种情况下的返回值应该是TRUE和GetLastError()
== NO_ERROR。在 Windows 7 上我得到 FALSE 和
GetLastError()
== ERROR_IO_PENDING。所以 WinApi 告诉我这是一个异步调用,但是当我查看测试时我发现它不是!我不是唯一发现这个“错误”的人:阅读 ReadFile MSDN 页面上的评论。
那么有什么解决办法呢?有人知道吗?丹尼斯发现这种奇怪的行为已经过去了 14 个月。
最佳答案
我不知道“c:\1.avi”文件的大小,但您提供给 Windows 的缓冲区大小(256M!)可能足以容纳该文件。所以windows决定读取整个文件并按照它喜欢的方式把它放在缓冲区中。您不会对 Windows 说“我想要异步”,而是说“我知道如何处理异步”。
只需将缓冲区大小更改为 1024,您的程序的行为就会完全相同,但仅读取 1024 字节(并返回 ERROR_IO_PENDING)。
一般来说,你做异步是因为你想在操作过程中做一些其他的事情。在此处查看示例:Testing for the End of a File ,因为它演示了异步 ReadFile。如果您更改样本的缓冲区并将其设置为一个大值,它的行为应该与您的完全一样。
PS:我建议你不要依赖时间样本来检查事情,使用返回码和事件
关于winapi - ReadFile 在 Win7 和 Win2k8 上不能异步工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4878868/