我需要异步读取文件
string read(string path) {
DWORD readenByte;
int t;
char* buffer = new char[512];
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, "read");
OVERLAPPED overlap;
overlap.hEvent = hEvent;
HANDLE hFile = CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(!hFile) {
Debug::error(GetLastError(), "fileAsync.cpp::read - ");
}
t = ReadFile(hFile, buffer, MAX_READ - 1, &readenByte, &overlap);
if(!t) {
Debug::error(GetLastError(), "fileAsync.cpp::read - ");
}
t = WaitForSingleObject(hEvent, 5000);
if(t == WAIT_TIMEOUT) {
Debug::error("fail to read - timeout, fileAsync.cpp::read");
}
buffer[readenByte] = '\0';
string str = buffer;
return str;
}
我在ReadFile上遇到错误 - 38:到达文件末尾
如何使用winapi在c ++中读取asynchroneusly文件?
答案 0 :(得分:5)
您的代码中有几个需要解决的错误,一些导致失败,另一些导致灾难性失败。
第一个错误导致您获得错误代码:您有一个未初始化的OVERLAPPED结构,指示以下ReadFile
调用从中存储的随机文件位置读取偏移和 OffsetHigh 成员。要解决此问题,请初始化数据:OVERLAPPED overlap = {0};
。
接下来,您不打开文件进行异步访问。要随后从文件中异步读取,您需要为{em> dwFlagsAndAttributes 调用CreateFile传递FILE_FLAG_OVERLAPPED
。如果你几个月没有去寻找一个错误(见What happens if you forget to pass an OVERLAPPED structure on an asynchronous handle?)。
ReadFile的文档解释说, lpNumberOfBytesRead 参数不用于异步I / O,您应该通过NULL
。这应该是显而易见的,因为异步ReadFile
调用在传输的字节数已知之前返回。要获得传输的有效负载的大小,请在异步I / O完成后调用GetOverlappedResult。
下一个错误只会导致内存泄漏。您正在动态分配buffer
,但从不致电delete[] buffer;
。删除缓冲区,或分配具有自动存储持续时间(char buffer[MAX_READ] = {0};
)的缓冲区,或使用C ++容器(例如std::vector<char> buffer(MAX_READ);
)。
另一个错误是,您尝试从std::string
构建buffer
:您选择的构造函数无法处理嵌入的NUL
字符。它会截断你拥有的任何东西。您需要调用std::string constructor采用明确的长度参数。但即便如此,如果文件的字符编码与std::string
不一致,您可能会厌倦垃圾。
最后,发出一个异步读取,然后是WaitForSingleObject
本质上是一个同步读取,并没有给你买任何东西。我假设这只是用于测试,而不是你的最终代码。完成此操作时请记住,只要异步读取操作正在进行,OVERLAPPED
结构就需要保持活动状态。
其他建议,不会立即解决错误:
您正在将std::string
传递给您在read
电话中使用的CreateFile
功能。 Windows始终使用UTF-16LE编码,在使用Visual Studio(以及可能还有其他Windows编译器)时映射到wchar_t
/ std::wstring
。传递std::string
/ const char*
有两个直接的缺点:
始终使用Unicode API(CreateFileW
)和UTF-16字符串(std::wstring
/ wchar_t
)。您还可以在编译器的命令行中定义预处理器符号UNICODE
(对于Windows API)和_UNICODE
(对于CRT),以免意外调用任何ANSI API。
您正在创建一个只能通过其HANDLE
值访问的事件对象,而不是其名称。您可以将NULL
作为 lpName 参数传递给CreateEvent。这可以防止潜在的名称冲突,这对于名称为"read"
的通用名称来说更为重要。
答案 1 :(得分:2)
1)您需要在CreateFile调用的第6个参数(FILE_FLAG_OVERLAPPED
)中包含标记dwFlagsAndAttributes
。这就是为什么重叠读取很可能失败的原因。
2)MAX_READ
的价值是多少?我希望它小于513,否则如果文件大于512字节会发生坏事。
3)重叠结构指针不是ReadFile
的{{1}}将为您提供预期的错误代码997(NULL
),因此您无法评估ERROR_IO_PENDING
致电t
后。
4)在异步操作的情况下,ReadFile
函数不存储您在调用中传递的指针中读取的字节,您必须在操作完成后自己查询重叠的结果。
这是一个小工作片段,我希望你能从中积累起来:
ReadFile