Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Using QNetworkAccessManager to download a file



  • Hi all,

    In the following example:

    downloader.h:

    #ifndef DOWNLOADER_H
    #define DOWNLOADER_H
    
    #include <QObject>
    #include <QNetworkAccessManager>
    #include <QNetworkRequest>
    #include <QNetworkReply>
    #include <QUrl>
    #include <QDateTime>
    #include <QFile>
    #include <QDebug>
    
    class Downloader : public QObject
    {
        Q_OBJECT
    public:
        explicit Downloader(QObject *parent = nullptr);
        void doDownload();
    
    public slots:
        void replyFinished(QNetworkReply*);
    
    private:
        QNetworkAccessManager* manager;
    };
    
    #endif // DOWNLOADER_H
    

    downloader.cpp:

    #include "downloader.h"
    
    Downloader::Downloader(QObject *parent) : QObject(parent){ }
    
    //**********************************************
    
    void Downloader::doDownload()
    {
        manager = new QNetworkAccessManager(this);
        connect(manager, &QNetworkAccessManager::finished, this, &Downloader::replyFinished);
        manager->get(QNetworkRequest(QUrl("http://qt-project.org")));
    }
    
    //******************************************************
    
    void Downloader::replyFinished(QNetworkReply* reply)
    {
        if(reply->error())
        {
            qDebug() << "ERROR!";
            qDebug() << reply->errorString();
        }
    
        else
        {
            qDebug() << "1) " << reply->header(QNetworkRequest::ContentTypeHeader).toString();
            qDebug() << "2) " << reply->header(QNetworkRequest::LastModifiedHeader).toDateTime().toString();
            qDebug() << "3) " << reply->header(QNetworkRequest::ContentLengthHeader).toULongLong();
            qDebug() << "4) " << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
            qDebug() << "5) " << reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
    
            QFile* file = new QFile("C:/Users/ME/Desktop/downloaded.txt");
    
            if(file->open(QFile::Append))
            {
                qDebug() <<"The text file is open";
                file->write(reply->readAll());
                file->flush();
                file->close();
            }
            delete file;
        }
    
        reply->deleteLater();
    }
    

    main.cpp:

    #include <QCoreApplication>
    #include "downloader.h"
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        Downloader d;
        d.doDownload();
    
        return a.exec();
    }
    

    Why nothing is written in the downloaded.txt file please? Is it because the server, here the qt website, doesn't send any data and ...ContentLengthHeader).toULongLong() is zero?



  • I think done! :)

    First I downloaded Win64 OpenSSL v1.1.1f EXE | MSI (experimental) 63MB Installer from https://slproweb.com/products/Win32OpenSSL.html. Then installed the program and went and copied the path: C:\Program Files\OpenSSL-Win64\bin. After these on Projects > Run > Run Environment > clicked on path and then the button "Append path" and pasted the above path.
    Now the program works for both "http" and "https" websites and the text file is also populated from the data received by QNetwork reply.

    It's 4:55 am here. It's time to sleep now. :)


  • Lifetime Qt Champion

    @tomy said in Using QNetworkAccessManager to download a file:

    QFile* file = new QFile

    There is no need to allocate file on the heap.

    Was the file opened successfully?
    Did you try

    qDebug() << reply->readAll()
    

    ?
    Also, if I open the URL in a browser I see that it is redirected to an HTTPS URL. Could be that you don't have working OpenSSL in your Qt set-up.



  • @jsulm

    In,

    QFile* file = new QFile("C:/Users/ME/Desktop/downloaded.txt");
    
           if(file->open(QFile::Append))
           {
               qDebug() <<"The text file is open";
               file->write(reply->readAll());
               file->flush();
               file->close();
           }
           delete file;
    

    I have deleted file right at the point where it's not anymore needed. Is that heap allocation deprecated? Any general rule to obey, please?

    The qDebug() <<"The text file is open"; works and outputs the message, so the file opens, I assume.

    you don't have working OpenSSL in your Qt set-up.

    On my Qt set-up? Will you explain it please?


  • Lifetime Qt Champion

    @tomy said in Using QNetworkAccessManager to download a file:

    Is that heap allocation deprecated?

    There is simply no need for heap allocation here. Also, stack allocation is a lot faster than heap.
    Look, isn't this simpler?

    QFile file("C:/Users/ME/Desktop/downloaded.txt");
    if(file.open(QFile::Append))
    {
           qDebug() <<"The text file is open";
           file.write(reply->readAll());
           file.flush();
           file.close();
    }
    

    And as additional bonus: you can't forget to delete it (as you could forget to put "delete file" there).

    Take a look at https://doc.qt.io/qt-5/ssl.html



  • @tomy just in case, this example may be of inspiration



  • @jsulm

    Take a look at https://doc.qt.io/qt-5/ssl.html

    Thanks. I did but it's very confusing. I've not done this before. Let me explain please:
    I downloaded openssl-1.1.1f and found the file opensslv.h in the include folder of it. Now should I add this file to "...\mingw73_64\bin" and include that header in the downloader.h?

    @Pablo-J-Rogina
    Thank you. Why does the code have C style!?
    Is this example not better?



  • @tomy said in Using QNetworkAccessManager to download a file:

    Is this example not better?

    It's another example from same author. If you feel comfortable with that, it's Ok. It has a fancy GUI I guess



  • I myself created the GUI part by code in a project under the name GuiHttpDownload as follows:

    GuiHttpDownload.h

    #ifndef GUIHTTPDOWNLOAD_H
    #define GUIHTTPDOWNLOAD_H
    
    #include <QWidget>
    #include <QNetworkAccessManager>
    #include <QNetworkRequest>
    #include <QNetworkReply>
    #include <QUrl>
    #include <QDateTime>
    #include <QFile>
    #include <QDebug>
    
    class QPushButton;
    class QTextEdit;
    class GuiHttpDownload : public QWidget
    {
        Q_OBJECT
    
    public:
        GuiHttpDownload(QWidget *parent = nullptr);
        ~GuiHttpDownload();
    
    public slots:
        void replyFinished(QNetworkReply*);
    
    private:
        QPushButton* download;
        QPushButton* quit;
        QTextEdit* textEdit;
        QNetworkAccessManager* manager;
    };
    #endif // GUIHTTPDOWNLOAD_H
    

    GuiHttpDownload.cpp

    #include "guihttpdownload.h"
    #include <QPushButton>
    #include <QTextEdit>
    #include <QHBoxLayout>
    #include <QVBoxLayout>
    
    GuiHttpDownload::GuiHttpDownload(QWidget *parent)
        : QWidget(parent)
    {
        download = new QPushButton("&Download");
        quit = new QPushButton("&Quit");
        textEdit = new QTextEdit;
        manager = new QNetworkAccessManager(this);
    
         connect(manager, &QNetworkAccessManager::finished,
                 this, &GuiHttpDownload::replyFinished);
         connect(download, &QPushButton::clicked, [this]() {
             this->manager->get(QNetworkRequest(QUrl("http://qt-project.org")));
         });
         connect(quit, &QPushButton::clicked, this, &GuiHttpDownload::close);
    
        QHBoxLayout* hLayout = new QHBoxLayout;
        hLayout->addWidget(download);
        hLayout->addWidget(quit);
    
        QVBoxLayout* vLayout = new QVBoxLayout;
        vLayout->addWidget(textEdit);
        vLayout->addLayout(hLayout);
    
        setLayout(vLayout);
    
        setWindowTitle("Download Test");
    }
    
    //*********************************************
    
    GuiHttpDownload::~GuiHttpDownload()
    {
        delete download;
        delete quit;
        delete manager;
    }
    
    //***************************************************************
    
    void GuiHttpDownload::replyFinished(QNetworkReply* reply)
    {
        if(reply->error())
        {
            textEdit->insertPlainText("ERROR!");
            textEdit->insertPlainText(reply->errorString());
        }
    
        else
        {
            textEdit->insertPlainText("1) " + reply->header(QNetworkRequest::ContentTypeHeader).toString());
            textEdit->insertPlainText("\n2) " + reply->header(QNetworkRequest::LastModifiedHeader).toDateTime().toString());
            textEdit->insertPlainText("\n3) " + reply->header(QNetworkRequest::ContentLengthHeader).toULongLong());
            textEdit->insertPlainText("\n4) " + reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt());
            textEdit->insertPlainText("\n5) " + reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString());
    
            QFile file("C:/Users/ME/Desktop/downloaded.txt");
    
            if(file.open(QFile::Append))
            {
                textEdit->insertPlainText("\n\nThe text file is open\n");
                file.write(reply->readAll());
                file.flush();
                file.close();
            }
        }
    
        reply->deleteLater();
    }
    

    main.cpp

    #include "guihttpdownload.h"
    
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        GuiHttpDownload w;
        w.show();
        return a.exec();
    }
    

    It works rather fine. But still I've not found the correct way to have working OpenSSL in my Qt set-up!
    @jsulm if possible, please help me on that.
    Is the way I stated on my above post right for the job? I didn't find a solution to use it and solve the problem either.



  • @tomy said in Using QNetworkAccessManager to download a file:

    But still I've not found the correct way to have working OpenSSL in my Qt set-up!

    Could you please state:

    1. the OS
    2. how did you installed Qt framework?
    3. what compiler are you using?


  • @Pablo-J-Rogina

    Could you please state:

    1. the OS

    Windows 10 x64

    1. how did you installed Qt framework?

    The online installer

    1. what compiler are you using?

    MinGW x64



  • @tomy so then it's very likely the OpenSSL DLLs cannot be found by your app.
    Please connect the QNetworkAccessManager::sslErrors() signal to a slot and check the error(s) there.



  • I think done! :)

    First I downloaded Win64 OpenSSL v1.1.1f EXE | MSI (experimental) 63MB Installer from https://slproweb.com/products/Win32OpenSSL.html. Then installed the program and went and copied the path: C:\Program Files\OpenSSL-Win64\bin. After these on Projects > Run > Run Environment > clicked on path and then the button "Append path" and pasted the above path.
    Now the program works for both "http" and "https" websites and the text file is also populated from the data received by QNetwork reply.

    It's 4:55 am here. It's time to sleep now. :)


Log in to reply