QFile enregistre les fichiers à la fermeture du programme, n'enregistre pas du tout ~ 500 Mo de fichiers

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

Question

Ouais les gars, c'est encore moi.J'ai le code suivant :

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

Et j'ai deux problèmes :

  1. Lorsque je clique sur le bouton, il télécharge les fichiers mais ne les écrit pas sur le disque dur.Je peux attendre 5, 10 minutes et rien.À ce stade, l’intégralité du fichier est stockée dans la mémoire du programme.Si je ferme mon programme, ils sont enregistrés sur le disque.

  2. Les fichiers volumineux (~ 500 Mo) ne sont pas du tout enregistrés.Lorsque je ferme mon programme, il plante instantanément.

Comment puis-je le modifier pour que mon programme enregistre les fichiers téléchargés « en temps réel » ?

Était-ce utile?

La solution

La non-interactivité est due au fait que re->readAll() sur un appareil de taille inconnue est un appel bloquant.Il continuera à lire jusqu'à ce que la demande soit terminée.

Le problème avec les fichiers volumineux est lié à la croissance du tableau d'octets contenant le fichier.À un moment donné, votre tableau d'octets fera, disons, 400 Mo, puis il devra croître pour atteindre 2 fois cette taille, vous devrez donc conserver ~ 1 Go à la fois, en deux gros morceaux, et en raison de la fragmentation de l'espace d'adressage, un la demande d'allocation échouera et votre programme plantera.

De petites modifications apportées à votre code génèrent le comportement souhaité :vous commencez à lire et à écrire en même temps, et vous reliez simplement les deux :

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);
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top