QFile salva i file su Program Esci, Wont Salva i file ~ 500 MB
-
20-12-2019 - |
Domanda
sì ragazzi, sono di nuovo io.Ho il seguente codice:
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();
}
.
E ho due problemi:
- .
-
Quando clicco sul pulsante scarica i file ma non lo scriverà su HDD.Posso aspettare 5, 10 minuti e niente.A questo punto, intero file è memorizzato all'interno della memoria del programma.Se chiudo il mio programma, vengono salvati su disco.
-
I file di grandi dimensioni (~ 500 MB) non vengono salvati affatto.Quando chiudo il mio programma, si blocca all'istante.
Come posso modificarlo, quindi il mio programma salverà i file scaricati "in tempo reale"?
Soluzione
La non interattività è perché re->readAll()
su un dispositivo con dimensioni sconosciute è una chiamata di blocco.Continuerà a leggere fino a quando la richiesta è terminata.
Il problema con i file di grandi dimensioni ha a che fare con la crescita dell'array Byte che contiene il file.Ad un certo punto, il tuo array di byte sarà, per dire 400mb, e poi dovrà crescere per dire 2x quella dimensione, quindi dovrai tenere ~ 1 GB contemporaneamente, in due grosse blocchi, e a causa della frammentazione dello spazio di indirizzoLa richiesta di assegnazione fallirà e il tuo programma si blocca.
Piccole modifiche al tuo codice rendimento del comportamento desiderato: inizi a leggere e scrivere contemporaneamente, e collega semplicemente i due:
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);
}
.