【问题标题】:QFile saves files on program quit, wont save ~500MB files at allQFile 在程序退出时保存文件,根本不会保存 ~500MB 文件
【发布时间】:2014-02-25 00:24:51
【问题描述】:

是的,伙计们,又是我。我有以下代码:

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)。当我关闭我的程序时,它会立即崩溃。

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

【问题讨论】:

  • 1) 你应该连接到finished(),而不是readyRead()。对于内存优化,您可以逐块读取,但是使用链式 readyRead。 2) 请显示崩溃的回溯。
  • Downloading a file with Qt? 的可能重复项

标签: c++ qt5 qnetworkaccessmanager qfile qeventloop


【解决方案1】:

非交互性是因为re-&gt;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);
}

【讨论】:

    猜你喜欢
    • 2014-06-03
    • 1970-01-01
    • 2014-12-06
    • 2015-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-09
    相关资源
    最近更新 更多