调用 readAll() 后不再无法从 QIODevice 检索数据。缓冲区刷新?

No longer unable to retrieve data from QIODevice after calling readAll(). Buffer flushed?

我刚刚在使用 QNetworkReply 时注意到一些事情,我无法在 Qt documentation 中为 QIODevice::readAll() 找到丝毫提示(QNetworkReply 继承了这个方法来自).

这是文档中的内容:

Reads all remaining data from the device, and returns it as a byte array.

This function has no way of reporting errors; returning an empty QByteArray can mean either that no data was currently available for reading, or that an error occurred.

假设我有以下连接:

connect(this->reply, &QIODevice::readyRead, this, &MyApp::readyReadRequest);

readyReadRequest() 广告位如下所示:

void MyApp::readyReadRequest()
{
    LOG(INFO) << "Received data from \"" << this->url.toString() << "\"";
    LOG(INFO) << "Data contents:\n" << QString(this->reply->readAll());
    this->bufferReply = this->reply->readAll();
}

我打电话给 this->bufferReplyMyAppQByteArray class 成员后,惊喜来了。我将它传递给 QXmlStreamReader 并做了:

while (!reader.atEnd())
{
    LOG(DEBUG) << "Reading next XML element";
    reader.readNext();
    LOG(DEBUG) << reader.tokenString();
}
if (reader.hasError())
{
    LOG(ERROR) << "Encountered error while parsing XML data:" << reader.errorString();
}

想象一下当我得到以下输出时我的惊讶:

2017-10-17 16:12:18,591 DEBUG [default] [void MyApp::processReply()][...] Reading next XML element

2017-10-17 16:12:18,591 DEBUG [default] [void MyApp::processReply()] [...] Invalid

2017-10-17 16:12:18,591 ERROR [default] Encountered error while parsing XML data: Premature end of document

通过调试我发现我的bufferReply此时是空的。我再次查看了文档,但没有找到任何提示在阅读完所有内容后从设备中删除数据(在我的例子中是网络回复)。

删除我打印字节数组的行或简单地将它移动到 this->bufferReply = this->reply->readAll(); 之后然后打印 class 成员的内容解决了这个问题:

void MyApp::readyReadRequest()
{
    LOG(INFO) << "Received data from \"" << this->url.toString() << "\"";
    this->bufferReply = this->reply->readAll();
    LOG(INFO) << "Data contents:\n" << QString(this->bufferReply);
}

但是我想知道是我做错了什么还是文档确实不完整。

由于 readAll() 不报告错误或数据在给定时间点不可用返回空字节数组是唯一暗示某些事情没有按预期工作的事实.

是的。当你调用 QIODevice::readAll() 2 次时,第二次你什么也得不到是正常的。都看完了,没啥可看的了。

这种行为在 IO 读取函数中是标准的:每次调用 read() 函数 return 都会读取下一条数据。由于 readAll() 读到最后,进一步调用 return 什么都没有。

但是,这并不一定意味着数据已被刷新。例如,当你读取一个文件时,它只是移动了 "cursor",你可以用 QIODevice::seek(0) 返回到文件的开头。对于 QNetworkReply,我猜数据只是被丢弃了。