c++ - QFile 在程序退出时保存文件,根本不会保存 ~500MB 文件

标签 c++ qt5 qnetworkaccessmanager qfile qeventloop

大家好,又是我。我有以下代码:

void MainWindow::on_startButton_clicked()
{
  QNetworkAccessManager *nam = new QNetworkAccessManager(this);
  QNetworkReply *re = nam->get(QNetworkRequest(QUrl("http://somesite/ai/iai.jpg")));
  QEventLoop loop;
  QObject::connect(reply, SIGNAL(readyRead()), &loop, SLOT(quit()));
  loop.exec();
  ui->dbgOut->insertHtml("<font color='green'>OK</font><br>");
  ui->dbgOut->insertHtml("##################################");
  //save
  QFile file("C:\\a.bin");
  file.open(QIODevice::WriteOnly);
  file.write(re->readAll());
  file.close();
}

我有两个问题:

  1. 当我点击按钮时,它会下载文件但不会将它们写入硬盘。我可以等 5、10 分钟,什么也没有。此时,整个文件存储在程序存储器中。如果我关闭我的程序,它们将保存在磁盘上。

  2. 大文件 (~500MB) 根本不保存。当我关闭我的程序时,它立即崩溃。

我如何编辑它以便我的程序“实时”保存下载的文件?

最佳答案

非交互性是因为 re->readAll() 在未知大小的设备上是一个阻塞调用。它会一直读取直到请求完成。

大文件的问题与保存文件的字节数组的增长有关。在某些时候,你的字节数组将是,比如说 400MB,然后它必须增长到那个大小的 2 倍,所以你必须一次保持 ~1GB,分为两个大块,并且由于地址空间碎片分配请求将失败,您的程序将崩溃。

对您的代码进行微小的更改会产生所需的行为:您立即开始阅读和写作,然后将两者链接起来:

class MainWindow {
  ...
  // You shouldn't be creating a new network access manager for each request.
  QScopedPointer<QNetworkAccessManager> m_nam;
  ...
};

void MainWindow::handleError(const QNetworkReply *) { ... }
void MainWindow::handleError(const QFile *) { ... }
void MainWindow::on_startButton_clicked()
{
  // Lazily create the network access manager once.
  if (!m_nam) m_nam.reset(new QNetworkAccessManager);
  // The file is destructed, and thus flushed and closed, when the
  // last shared pointer to this file is destructed.
  QSharedPointer<QFile> output(new QFile("C:\\a.bin"));
  if (!output->open(QIODevice::WriteOnly)) return;
  QNetworkReply *reply = m_nam->get(QNetworkRequest(QUrl("http://somesite/ai/iai.jpg")));
  // The lambda syntax creates a functor object that holds a copy
  // of the reply pointer and the output file pointer.
  // This functor will be destructed when the reply is destructed.
  QObject::connect(reply, &QIODevice::readyRead, [this, output, reply]{
    QByteArray data(reply->bytesAvailable(), Qt::Uninitialized);
    qint64 in = reply->read(data.data(), data.size());
    qint64 out = output->write(in);
    if (in < 0) {
      handleError(reply); 
      reply->deleteLater();
    }
    else if (out != in) {
      handleError(output.data());
      reply->deleteLater();
    }
  });
  // The reply will self-destruct when finished, thus deleting the file
  // instance.
  QObject::connect(reply, &QNetworkReply::finished, reply, &QObject::deleteLater);
}

关于c++ - QFile 在程序退出时保存文件,根本不会保存 ~500MB 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22002095/

相关文章:

c++ - 为什么将 char**(或任何 T**)转换为 void** 无效?

c++ - QTextEdit : how can I modify text being pasted into editor?

c++ - 如何使我的 Qt 项目静态化 (.exe)

c++ - Qt 从另一个类设置按钮颜色

c++ - QNetworkReply 响应是否有数据限制?

C++ 检查是否为 Windows 10

c++ - "xvalue has identity",为什么我不能计算它的地址

c++ - 嵌套结构

qt - 错误: QNetworkReply: No such file or directory

c++ - 如何使用 Qt 网络类防止关机竞争条件