Pregunta

Sí, chicos, soy yo otra vez.Tengo el siguiente código:

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();
}

y tengo dos problemas:

  1. Cuando hago clic en el botón Descarga archivos, pero no los escribirá en HDD.Puedo esperar 5, 10 minutos y nada.En este momento, todo el archivo se almacena dentro de la memoria del programa.Si cierro mi programa, se guardan en el disco.

  2. archivos grandes (~ 500 MB) no se guardan en absoluto.Cuando cierro mi programa, se estrella al instante.

  3. ¿Cómo puedo editarlo para que mi programa guarde los archivos descargados "en tiempo real"?

¿Fue útil?

Solución

La no interactividad es porque re->readAll() en un dispositivo con un tamaño desconocido es una llamada de bloqueo.Seguirá leyendo hasta que la solicitud esté terminada.

El problema con los archivos grandes tiene que ver con el crecimiento de la matriz de bytes que posee el archivo.En algún momento, su matriz de bytes será, digamos 400 MB, y luego tendrá que crecer para decir 2x ese tamaño, por lo que tendrá que contener ~ 1GB a la vez, en dos trozos grandes, y debido a la fragmentación del espacio de direcciones unLa solicitud de asignación fallará y su programa se bloquea.

Cambios pequeños en el comportamiento deseado de su rendimiento de código: comienza a leer y escribir a la vez, y simplemente vincule los dos:

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);
}

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top