Qt中readall返回二进制数据么
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Qt中readall返回二进制数据么相关的知识,希望对你有一定的参考价值。
参考技术A 返回的。Qt使用QFile和QDataStream进行二进制数据文件的读写,QFile负责文件的IO设备接口,即与文件的物理交互。QDataStream以数据流的方式读取文件内容或写入文件内容。
QtCreator是一个用于Qt开发的轻量级跨平台集成开发环境。QtCreator可带来两大关键益处:提供首个专为支持跨平台开发而设计的集成开发环境(IDE),并确保首次接触Qt框架的开发人员能迅速上手和操作。即使不开发Qt应用程序,QtCreator也是一个简单易用且功能强大的IDE。
使用 QNetworkreply::readAll 下载大文件冻结几秒钟
【中文标题】使用 QNetworkreply::readAll 下载大文件冻结几秒钟【英文标题】:Download big files with QNetworkreply::readAll freeze for a few seconds 【发布时间】:2016-11-05 20:56:22 【问题描述】:我使用了像 doc http://doc.qt.io/qt-4.8/qnetworkaccessmanager.html 这样的例子
我创建了一个startDownload
:
connect(pushButton, SIGNAL(clicked(bool)), this, SLOT(startDownload(bool)));
在startDownload(bool)
我放了这个:
file = new QFile("C:/foo/bar/bigfile.7z");
file->open(QIODevice::WriteOnly);
QNetworkRequest request;
request.setUrl(QUrl("http://localhost/bigfile.7z"));
request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");
QNetworkReply *reply = manager->get(request);
connect(reply, SIGNAL(readyRead()), this, SLOT(slotReadyRead()));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(slotError(QNetworkReply::NetworkError)));
connect(reply, SIGNAL(sslErrors(QList<QSslError>)),
this, SLOT(slotSslErrors(QList<QSslError>)));
在slotReadyRead
我放了这个:
file->write(reply->readAll());
但是下载到最后会出现2秒的小卡顿,然后恢复正常,下载完成。仅当我尝试传输的文件很大时才会出现此问题。
【问题讨论】:
我试图为您的问题写一个minimal example。我计算了每个file->write(reply->readAll())
调用的时间,大多数调用花费了 0 毫秒,最后一次调用(在下载结束时)没有你描述的显着差异(我尝试了我的本地文件的代码大约 1GB 大小的网络)。也许是代码中的另一件事使事情变慢?尝试测量函数调用的持续时间,以确保确实是这个调用导致了问题。
@Mike 这个问题只出现在 GUI 应用程序中,例如QMainWindow
问题出现在 GUI 中,因为回调花费了 很多 时间来完成并返回到事件循环。在我的测试中,我只是测量在file->write(reply->readAll());
中花费的时间,以确保下载结束时确实需要 2 秒。但事实证明,其实用不了那么长时间,你的输出不一样吗?
@Mike 18mb => i.stack.imgur.com/qSU2n.png in online server, 300mb in localhost => i.stack.imgur.com/m58Wn.png 我认为问题因网络而异。
@Mike 是的,看看没有 setReadBufferSize => i.stack.imgur.com/OxhdH.png, with setReadBufferSize => i.stack.imgur.com/bMZQQ.png 我正在做一些测试,会准备一个答案。
【参考方案1】:
这是预期的行为。 QIODevice::readAll()
将阻塞线程直到下载完成。 QFile::write()
也可能会阻塞,具体取决于磁盘速度和缓存策略。如果文件足够大,readAll()
方法也可能会消耗相当多的 RAM。
最简单的解决方案是使用read()
而不是readAll()
以更小的块下载文件。
话虽如此,要找到从网络读取并写入磁盘的完美缓冲区大小并不容易;这将取决于网络连接如何响应与磁盘写入速度。
【讨论】:
有道理,能举个例子吗?谢谢! 或者如果你想使用阻塞api,不要阻塞主线程——使用工作线程。 您必须在询问之前阅读文档。这就是拥有文档的全部意义所在。您只能就更复杂或未涵盖的主题提出问题,或者您是否遇到问题。这个网站不是为了帮助那些懒得阅读文档的人。很多人都懒得看,也懒得找,直接问。那只是懒惰。它不应该得到奖励。它不会帮助你变得更好,它会让你更懒惰。 这不是什么复杂的事情,把下载的代码放在一个QObject中,创建对象和线程,把对象移动到线程中,然后它的函数就会在那个线程中执行。使用信号排队下载,下载完成时使用信号。那是简单的事件驱动异步编程。如果您遇到特定问题并陷入困境,他们会提出问题,但仅在您搜索之后。并且不要亲自投票,它们不是个人的,这只是意味着您的问题不符合社区的标准。但有时它只是“猴子看猴子做”;)readAll()
被记录为从设备返回剩余数据。它确实不阻塞线程。查看它的implementation,它只是调用read()
来填充数组。【参考方案2】:
在尝试使用@Mike代码后,我注意到readyRead
final中读取的数据比之前的要高很多,导致写入文件很慢:
最后两个读数是:
-
46080000 字节 - 写入需要约 1.6 秒。
227323951 字节 - 写入需要约 2.7 秒。
它根据网络类型和速度而变化,允许缓冲区是否很大。
在 GUI 应用程序中会导致大约 4 秒的“冻结”感。
对于我使用QNetworkReply::setReadBufferSize
的有限缓冲区,请查看区别:
读数为 1048576 字节 - 写入需要 2 到 10 毫秒。
【讨论】:
@KubaOber 我明白了,但这是唯一有效的方法,我遵循了@ddriver
的指导,你能告诉我一个更好的方法吗?
您正在泄露网络访问管理器的实例。由于下载工作者总是需要网络访问管理器,您可以将其添加为成员并按值保存,无需在每次调用 process()
时重新创建它。以上是关于Qt中readall返回二进制数据么的主要内容,如果未能解决你的问题,请参考以下文章
Qt serial.readall 在 5.3.1 中不起作用