Nik*_*ita 0 c++ winapi asynchronous
我需要异步读取文件
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;
}
Run Code Online (Sandbox Code Playgroud)
我在ReadFile上遇到错误 - 38:到达文件末尾
如何使用winapi在c ++中读取asynchroneusly文件?
您的代码中有几个需要解决的错误,一些导致失败,另一些导致灾难性失败.
第一个错误会导致您获得错误代码:您有一个未初始化的OVERLAPPED结构,指示以下ReadFile
调用从存储在Offset和OffsetHigh成员中的随机文件位置读取.要解决此问题,请初始化数据:OVERLAPPED overlap = {0};
.
接下来,您不打开异步访问文件.要随后从文件中异步读取,您需要为dwFlagsAndAttributes调用CreateFile传递.如果你不这样做几个月就要找错了(如果忘记在异步句柄上传递OVERLAPPED结构,会发生什么?).FILE_FLAG_OVERLAPPED
ReadFile的文档解释说,lpNumberOfBytesRead参数不用于异步I/O,NULL
而是应该传递.这应该是显而易见的,因为异步ReadFile
调用在传输的字节数已知之前返回.要获得传输的有效负载的大小,请在异步I/O完成后调用GetOverlappedResult.
下一个bug只会导致内存泄漏.你是动态分配buffer
,但从不打电话delete[] buffer;
.删除缓冲区,或分配具有自动存储持续时间(char buffer[MAX_READ] = {0};
)的缓冲区,或使用C++容器(例如std::vector<char> buffer(MAX_READ);
).
另一个错误是,你尝试std::string
从你buffer
的构造中构建一个:你选择的构造函数不能处理嵌入NUL
字符的内容.它会截断你拥有的任何东西.您需要使用显式长度参数调用std :: string构造函数.但即便如此,如果文件的字符编码std::string
并不同意,你可能会厌倦垃圾.
最后,发出一个异步读取,然后WaitForSingleObject
本质上是一个同步读取,并没有给你买任何东西.我假设这只是用于测试,而不是你的最终代码.在完成此操作时请记住OVERLAPPED
,只要异步读取操作正在进行,结构就需要保持活动状态.
其他建议,不会立即解决错误:
您正在传递std::string
给您read
在CreateFile
呼叫中使用的功能.Windows始终使用UTF-16LE编码,映射到wchar_t
/ std::wstring
何时使用Visual Studio(以及可能还有其他Windows编译器).传递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"
.