QT loading a big file error

When I try to upload a file up to 50 MB in size, not a problem, but with large files I get the following error err

 void MainWindow::downloadFile() {
           QNetworkRequest requests;
           requests.setUrl(QUrl("https://urlToFile"));

           QSslConfiguration configSsl = QSslConfiguration::defaultConfiguration();
           configSsl.setProtocol(QSsl::AnyProtocol);
           requests.setSslConfiguration(configSsl);
           QNetworkAccessManager *manager5 = new QNetworkAccessManager(this);
           QNetworkReply *reply5;
           reply5 = manager5->get( requests );
           connect(manager5, SIGNAL(finished(QNetworkReply*)), this, SLOT(downloadFinished(QNetworkReply*)));
}


    void MainWindow::downloadFinished(QNetworkReply *data) {
     QFile localFile("fileName");
        if (!localFile.open(QIODevice::WriteOnly))
            return;
        localFile.write(data->readAll());
        localFile.close();
    }
0
source share
1 answer

In your code, you save the entire file in memory until the download process is complete (that is, when a signal is issued QNetworkAccessManager::finished()). Of course, this is not the best way to handle large files.

Remember that QNetworkReplyis QIODevice. This means that you must use the signal readyRead()to save data blocks to disk as soon as they are received from the network, in order to avoid storing the entire file in memory until the download is complete.

Here is a minimal complete example:

#include <QtNetwork>

int main(int argc, char* argv[]){
    QCoreApplication a(argc, argv);

    QNetworkAccessManager nam;
    QFile file("downloadedFile.xxx");
    if(!file.open(QIODevice::ReadWrite)) return 1;
    QNetworkRequest request(QUrl("http://download_url/..."));
    QNetworkReply* reply = nam.get(request);

    QObject::connect(reply, &QNetworkReply::readyRead, [&]{
        //this will be called every time a chunk of data is received
        QByteArray data= reply->readAll();
        qDebug() << "received data of size: " << data.size();
        file.write(data);
    });

    //use the finished signal from the reply object to close the file
    //and delete the reply object
    QObject::connect(reply, &QNetworkReply::finished, [&]{
        qDebug() << "finished downloading";
        QByteArray data= reply->readAll();
        file.write(data);
        file.close();
        reply->deleteLater();
        a.quit();
    });

    return a.exec();
}

Update:

FileDownloader, QNetworkAccessManager. :

screenshot

#include <QtWidgets>
#include <QtNetwork>

//downloads one file at a time, using a supplied QNetworkAccessManager object
class FileDownloader : public QObject{
    Q_OBJECT
public:
    explicit FileDownloader(QNetworkAccessManager* nam, QObject* parent= nullptr)
        :QObject(parent),nam(nam)
    {

    }
    ~FileDownloader(){
        //destructor cancels the ongoing dowload (if any)
        if(networkReply){
            a_abortDownload();
        }
    }

    //call this function to start downloading a file from url to fileName
    void startDownload(QUrl url, QString fileName){
        if(networkReply) return;
        destinationFile.setFileName(fileName);
        if(!destinationFile.open(QIODevice::WriteOnly)) return;
        emit goingBusy();
        QNetworkRequest request(url);
        networkReply= nam->get(request);
        connect(networkReply, &QIODevice::readyRead, this, &FileDownloader::readData);
        connect(networkReply, &QNetworkReply::downloadProgress,
                this, &FileDownloader::downloadProgress);
        connect(networkReply, &QNetworkReply::finished,
                this, &FileDownloader::finishDownload);
    }

    //call this function to abort the ongoing download (if any)
    void abortDownload(){
        if(!networkReply) return;
        a_abortDownload();
        emit backReady();
    }

    //connect to the following signals to get information about the ongoing download
    Q_SIGNAL void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
    Q_SIGNAL void downloadSuccessful();
    Q_SIGNAL void downloadError(QString errorString);
    //the next two signals are used to indicate transitions between busy and
    //ready states of the file downloader, they can be used to update the GUI
    Q_SIGNAL void goingBusy();
    Q_SIGNAL void backReady();

private:
    Q_SLOT void readData(){
        QByteArray data= networkReply->readAll();
        destinationFile.write(data);
    }
    Q_SLOT void finishDownload(){
        if(networkReply->error() != QNetworkReply::NoError){
            //failed download
            a_abortDownload();
            emit downloadError(networkReply->errorString());
        } else {
            //successful download
            QByteArray data= networkReply->readAll();
            destinationFile.write(data);
            destinationFile.close();
            networkReply->deleteLater();
            emit downloadSuccessful();
        }
        emit backReady();
    }
    //private function, cleans things up when the download is aborted
    //(due to an error or user interaction)
    void a_abortDownload(){
        networkReply->abort();
        networkReply->deleteLater();
        destinationFile.close();
        destinationFile.remove();
    }

    QNetworkAccessManager* nam;
    QUrl downloadUrl;
    QFile destinationFile;
    QPointer<QNetworkReply> networkReply;
};

//A sample GUI application that uses the above class
class Widget : public QWidget{
    Q_OBJECT
public:
    explicit Widget(QWidget* parent= nullptr):QWidget(parent){
        layout.addWidget(&lineEditUrl, 0, 0);
        layout.addWidget(&buttonDownload, 0, 1);
        layout.addWidget(&progressBar, 1, 0);
        layout.addWidget(&buttonAbort, 1, 1);
        layout.addWidget(&labelStatus, 2, 0, 1, 2);
        lineEditUrl.setPlaceholderText("URL to download");
        connect(&fileDownloader, &FileDownloader::downloadSuccessful,
                this, &Widget::downloadFinished);
        connect(&fileDownloader, &FileDownloader::downloadError,
                this, &Widget::error);
        connect(&fileDownloader, &FileDownloader::downloadProgress,
                this, &Widget::updateProgress);
        connect(&buttonDownload, &QPushButton::clicked,
                this, &Widget::startDownload);
        connect(&buttonAbort, &QPushButton::clicked,
                this, &Widget::abortDownload);

        showReady();
        //use goingBusy() and backReady() from FileDownloader signals to update the GUI
        connect(&fileDownloader, &FileDownloader::goingBusy, this, &Widget::showBusy);
        connect(&fileDownloader, &FileDownloader::backReady, this, &Widget::showReady);
    }

    ~Widget() = default;

    Q_SLOT void startDownload(){
        if(lineEditUrl.text().isEmpty()){
            QMessageBox::critical(this, "Error", "Enter file Url", QMessageBox::Ok);
            return;
        }
        QString fileName =
                QFileDialog::getSaveFileName(this, "Destination File");
        if(fileName.isEmpty()) return;
        QUrl url= lineEditUrl.text();
        fileDownloader.startDownload(url, fileName);
    }
    Q_SLOT void abortDownload(){
        fileDownloader.abortDownload();
    }

    Q_SLOT void downloadFinished(){
        labelStatus.setText("Download finished successfully");
    }
    Q_SLOT void error(QString errorString){
        labelStatus.setText(errorString);
    }
    Q_SLOT void updateProgress(qint64 bytesReceived, qint64 bytesTotal){
        progressBar.setRange(0, bytesTotal);
        progressBar.setValue(bytesReceived);
    }
private:
    Q_SLOT void showBusy(){
        buttonDownload.setEnabled(false);
        lineEditUrl.setEnabled(false);
        buttonAbort.setEnabled(true);
        labelStatus.setText("Downloading. . .");
    }
    Q_SLOT void showReady(){
        buttonDownload.setEnabled(true);
        lineEditUrl.setEnabled(true);
        buttonAbort.setEnabled(false);
        progressBar.setRange(0,1);
        progressBar.setValue(0);
    }

    QGridLayout layout{this};
    QLineEdit lineEditUrl;
    QPushButton buttonDownload{"Start Download"};
    QProgressBar progressBar;
    QPushButton buttonAbort{"Abort Download"};
    QLabel labelStatus{"Idle"};
    QNetworkAccessManager nam;
    FileDownloader fileDownloader{&nam};
};

int main(int argc, char* argv[]){
    QApplication a(argc, argv);

    Widget w;
    w.show();

    return a.exec();
}

#include "main.moc"
+3

Source: https://habr.com/ru/post/1690068/


All Articles