QFile сохраняет файлы при выходе из программы, вообще не сохраняет файлы размером ~ 500 МБ.

StackOverflow https://stackoverflow.com//questions/22002095

Вопрос

Да, ребята, это снова я.У меня есть следующий код:

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. Большие файлы (~500 МБ) вообще не сохраняются.Когда я закрываю программу, она мгновенно вылетает.

Как я могу отредактировать его, чтобы моя программа сохраняла загруженные файлы «в реальном времени»?

Это было полезно?

Решение

Неинтерактивность объясняется тем, что re->readAll() на устройстве неизвестного размера происходит блокировка вызова.Он будет продолжать чтение до тех пор, пока запрос не будет завершен.

Проблема с большими файлами связана с увеличением массива байтов, в котором хранится файл.В какой-то момент ваш байтовый массив составит, скажем, 400 МБ, а затем ему придется вырасти, скажем, в 2 раза, поэтому вам придется хранить ~ 1 ГБ одновременно, двумя большими частями, и из-за фрагментации адресного пространства запрос на выделение завершится неудачно, и ваша программа выйдет из строя.

Небольшие изменения в вашем коде приводят к желаемому поведению:вы начинаете читать и писать одновременно и просто связываете их:

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);
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top