Ale*_*iuk 4 c++ winapi boost boost-asio
我无法65536使用boost::asio::windows::stream_handle异步方式从文件中读取超过字节的字节数.
从65537第一个字节开始,缓冲区包含文件最开头的数据,而不是预期的数据.
这是一个代码示例,它重现了这个问题:
auto handle = ::CreateFile(L"BigFile.xml", GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr);
boost::asio::io_service ios;
boost::asio::windows::stream_handle streamHandle(ios, handle);
const auto to_read_bytes = 100000;
char buffer[to_read_bytes];
boost::asio::async_read(streamHandle, boost::asio::buffer(buffer, to_read_bytes), [](auto &ec, auto read) {
std::cout << "Bytes read: " << read << std::endl;
});
ios.run();
auto bufferBegin = std::string(buffer, 38);
auto bufferCorrupted = std::string(buffer + 65536, 38); // <- it contains bytes from the beginning of the file
std::cout << "offset 0: " << bufferBegin << std::endl;
std::cout << "offset 65536: " << bufferCorrupted << std::endl;
::CloseHandle(handle);
Run Code Online (Sandbox Code Playgroud)
该代码产生一个输出:
> Bytes read: 100000
> offset 0: <?xml version="1.0" encoding="UTF-8"?>
> offset 65536: <?xml version="1.0" encoding="UTF-8"?>
Run Code Online (Sandbox Code Playgroud)
源文件大于65536.
这可以通过boost 1.61 + VS2015重现.此问题还在于提升1.55 + VS2010.
操作系统包括:Windows 7和Windows Server 2008R2.
我的问题是:
1.是,在已知的限制boost::asio或WinAPI?
2.如果是已知限制,读取数据的缓冲区的安全大小是多少?有一个65536大小的缓冲区是否安全,或者它应该更小?
正如Tanner Sansbury所说,你打开了一个文件,FILE_FLAG_OVERLAPPED但你正试图将它用作流.它不是.
async_read()基本上是这个循环asio/impl/read.hpp:
for (;;)
{
stream_.async_read_some(buffers_, ASIO_MOVE_CAST(read_op)(*this));
buffers_.consume(bytes_transferred);
total_transferred_ += bytes_transferred;
if (!ec && bytes_transferred == 0)
break;
}
Run Code Online (Sandbox Code Playgroud)
一次调用中将读取的实际最大字节数来自completion_condition.hpp:
enum default_max_transfer_size_t { default_max_transfer_size = 65536 };
Run Code Online (Sandbox Code Playgroud)
问题是async_read_some()上面的呼吁.您会注意到没有偏移量可以告诉它从哪里开始阅读.因为您正在使用异步读取(在Windows上也称为"重叠"),所以必须为每次读取指定偏移量.
这是最终的结果,在asio/detail/impl/win_iocp_handle_service.ipp:
DWORD bytes_transferred = 0;
op->Offset = offset & 0xFFFFFFFF;
op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
BOOL ok = ::ReadFile(impl.handle_, buffer.data(),
static_cast<DWORD>(buffer.size()),
&bytes_transferred, op);
Run Code Online (Sandbox Code Playgroud)
op->Offset并且op->OffsetHigh始终为0.缓冲区内的指针将正确前进,但每个块都将从文件的开头读取.
有一个async_read_some_at()可用的,你应该使用它,以及windows::random_access_handle.这将正确设置Offset和OffsetHigh成员.您必须跟踪自己读取的字节数.
OVERLAPPED结构的文档说明了这一点:
Offset和OffsetHigh成员一起表示64位文件位置.它是从文件或类文件设备的开头偏移的字节,由用户指定; 系统不会修改这些值.调用进程必须在将OVERLAPPED结构传递给使用偏移量的函数(例如ReadFile或WriteFile(及相关)函数)之前设置此成员.
同步和异步I/O中还有这部分:
系统不会将文件指针保存在支持文件指针(即寻找设备)的文件和设备的异步句柄上,因此必须将文件位置传递给OVERLAPPED结构的相关偏移数据成员中的读写函数. .有关更多信息,请参阅WriteFile和ReadFile.
| 归档时间: |
|
| 查看次数: |
614 次 |
| 最近记录: |