Evgenii Legotckoi
Evgenii LegotckoiDec. 13, 2015, 9:58 p.m.

Qt/C++ - Lesson 035. Downloading files via HTTP with QNetworkAccessManager

To work with a network other than using QTcpSocket or QUdpSocket classes can use QNetworkAccessManager. This class provides the functionality to send requests across a network and get answers and easy to work with the HTTP protocol.

Therefore I propose to write an application that will allow download xml-file from the website and write it to a file on your PC.

Application logic is as follows:

  1. Download file;
  2. Write it on a local drive at the following path C:/example/file.xml;
  3. Read the recorded file and display the data in QTextEdit.

Project structure for work with HTTP

The project structure is as follows:

  • DownloadHttp.pro - the profile of the project;
  • main.cpp - the main file of the application;
  • widget.h - header file of the application window;
  • widget.cpp - file source code of the application window;
  • downloader.h - class header file for downloading the file;
  • doqnloader.cpp - class source code file to download the file.

DownloadHttp.pro and main.cpp

main.cpp is created by default and is not modified, whereas in the file DownloadHttp.pro need to connect network module.

#-------------------------------------------------
#
# Project created by QtCreator 2015-12-13T21:02:32
#
#-------------------------------------------------

QT       += core gui network

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = DownloadHttp
TEMPLATE = app


SOURCES += main.cpp\
        widget.cpp \
    downloader.cpp

HEADERS  += widget.h \
    downloader.h

FORMS    += widget.ui

widget.ui

The application window is a button, pressing which will be the launch of download data from a website and a QTextEdit, which will put the data from a saved file.

widget.h

The header file of the application window. In it we connect Downloader class header file, which will be responsible for data download from the website and save it to a file. Naturally we declare an object of this class Downloader . Also available ad slots signatures for reading data from the saved at the end of downloading the file.

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QFile>

#include <downloader.h>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private slots:
    void readFile();

private:
    Ui::Widget *ui;
    Downloader *downloader;
};

#endif // WIDGET_H

widget.cpp

In the source code, there are two connections of signals to the slots. Connect One is responsible for processing pressing, and the second for reading data from the file at the end of the file download.

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    downloader = new Downloader(); 

    connect(ui->pushButton, &QPushButton::clicked, downloader, &Downloader::getData);
    connect(downloader, &Downloader::onReady, this, &Widget::readFile);

}

Widget::~Widget()
{
    delete ui;
}

void Widget::readFile()
{
    QFile file("C:/example/file.xml");
    if (!file.open(QIODevice::ReadOnly)) 
            return; 
    ui->textEdit->setText(file.readAll());
}

donwloader.h

In it we declare an instance of QNetworkAccesManager, as well as methods for initializing the request to the site's URL and the processing of the response.

#ifndef DOWNLOADER_H
#define DOWNLOADER_H

#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QFile>
#include <QUrl>
#include <QDebug>

class Downloader : public QObject
{
    Q_OBJECT
public:
    explicit Downloader(QObject *parent = 0);

signals:
    void onReady();

public slots:
    void getData();     
    void onResult(QNetworkReply *reply);    

private:
    QNetworkAccessManager *manager; 
};

#endif // DOWNLOADER_H

downloader.cpp

ATTENTION !!! - Check the availability of the URL from the example before running the application, not to bang your head against the wall, if the site is simply not available. And it is better to replace the URL, to which you want to reach. And perhaps it makes sense to change the file extension to txt.

#include "downloader.h"

Downloader::Downloader(QObject *parent) : QObject(parent)
{
    // Initialize manager ...
    manager = new QNetworkAccessManager();
    // ... and connect the signal to the handler 
    connect(manager, &QNetworkAccessManager::finished, this, &Downloader::onResult);
}

void Downloader::getData()
{
    QUrl url("http://www.mtbank.by/currxml.php"); 
    QNetworkRequest request;    
    request.setUrl(url);        
    manager->get(request);      
}

void Downloader::onResult(QNetworkReply *reply)
{
    // If an error occurs in the process of obtaining data
    if(reply->error()){
        // We inform about it and show the error information
        qDebug() << "ERROR";
        qDebug() << reply->errorString();
    } else {
        // Otherwise we create an object file for use with
        QFile *file = new QFile("C:/example/file.xml");
        // Create a file, or open it to overwrite ...
        if(file->open(QFile::WriteOnly)){
            file->write(reply->readAll());  // ... and write all the information from the page file
            file->close();                  // close file
        qDebug() << "Downloading is completed";
        emit onReady(); // Sends a signal to the completion of the receipt of the file
        }
    }
}

Result

As a result, you get an application that get data from a page of the site and displays in a QTextEdit, as shown in the following figure. Demonstration application is available in the video tutorial.

Link to the project download in zip-archive: downloadhttp.zip

Video

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

C
  • April 21, 2017, 11:18 p.m.

Здравствуйте! Когда тестировал ваш проект в режиме Debug выводит такую ошибку:

-1: error: Exception at 0x74f3b782, code: 0xd: , flags=0x1 (execution cannot be continued) (first chance)
после закрытия программы. Также и с моим проектом. Я искал ошибку и нашел ошибку вот в этой строке: manager = new QNetworkAccessManager(); Также и у меня когда создаю обект класса QNetworkAccessManager. В чем пожет быть проблема? Спасибо.
Evgenii Legotckoi
  • April 21, 2017, 11:40 p.m.

Здравствуйте! Не знаю. На всякий случай я скачал проект и проверил сейчас у себя его работу, но никаких исключений не выкидывает. Проверял на Qt 5.8 GCC 64 bit под Ubuntu 16.04. Проект работает стабильно.

Какой версией Qt пользуетесь?

C
  • April 22, 2017, 12:08 a.m.

Я использую Qt 5.7.1 с Microsoft Visual Studio 2015 (Windows 10) и на Qt 5.9.0 Beta 2 также. У меня мой и ваш проект работает стабильно, но если через Debug тестировать и закрыть программу то такая ошибка появляется. Пробовал через Visual Studio 2015 отлаживать, но выводит ошибку:

Exception thrown at 0x74CCB782 (KernelBase.dll) in MyTestApp.exe: 0x0000071A: The remote procedure call was canceled, or if a call time-out was specified, the call timed out. If there is a handler for this exception, the program may be safely continued.
Или иногда эту ошибку:
Exception thrown at 0x74CCB782 (KernelBase.dll) in MyTestApp.exe: 0x0000000D: The data is invalid.
После выводит код ассемблера:
74CCB782 mov ecx,dword ptr [esp+54h]
К примеру на Windows 8.1 x64 тестировал то такую ошибку выводит как предупреждение: -1: error: Exception at 0x74f3b782, code: 0xd: , flags=0x1 (execution cannot be continued) (first chance) А на Windows 10 как ошибку. Не могу точно найти где ошибка, но если закоментировать код инициализации QNetworkAccessManager: manager = new QNetworkAccessManager(); тогда ошибки нет и соотвественно не работает подключение сети в программе.
Evgenii Legotckoi
  • April 22, 2017, 12:33 a.m.

Не похоже, чтобы это была проблема с Qt или ошибкой в коде. У меня такой проблемы как у вас не возникает. Проверил на следующем:

  1. Ubuntu 16.04 - GCC 64 bit - Qt5.8
  2. Windows 7 - MinGIW 32 bit - Qt5.7
  3. Windows 7 - MSVC 2015 - Qt5.7

Исключения по окончании работы не выбрасываются. У вас фигурирует в исключениях KernelBase.dll . Скорее всего это или придурь компилятора или сама библиотека кривая.

Но для очистки совести могу посоветовать передать указатель на parent объект при создании объекта QNetworkAccessManager

manager = new QNetworkAccessManager(this);
C
  • April 22, 2017, 12:57 a.m.

Да, и если указать parent (manager = new QNetworkAccessManager(this);) также ошибка. Я вот что еще заметил когда тестировал на Visual Studio 2015, Thread: [1328]wlanapi.dll!_NotificationApcThreadProc@4, то есть ошибка/сбой программы в этой функции, но у меня нет подключения к wlanapi (библиотеки WiFi) в программе, значит ошибка происходит только на Windows 10 и с библиотекой Qt (Qt5Networkd.dll/Qt5Network.dll).

Evgenii Legotckoi
  • April 22, 2017, 10:32 a.m.

Считаю, что библиотека Qt Network работает нормально. Дело в том, что данная библиотека перебирает все возможные варианты подключений, в том числе и wi-fi подключения, когда пытается найти выход в интернет. Мне думается, что тут исключительно локальная проблема с системными библиотеками на Windows 10.

Zeland
  • March 1, 2019, 3:12 a.m.

Евгений, спасибо за полезную статью. Немного отредактировал добавленные к уроку файлы, чтобы запустить программу на версии фреймворма Qt 5.10.
DownloadHttp.zip DownloadHttp.zip

Evgenii Legotckoi
  • March 1, 2019, 4:46 p.m.

Вам спасибо за дополнение.

F
  • Sept. 19, 2019, 3:45 p.m.

А вот как выгрузить файл на сервер по http протоколу? Допустим на regRu. И как получить путь файла, которой отображается в файловом менеджере regRu, чтобы загрузить его.

Evgenii Legotckoi
  • Sept. 25, 2019, 1:53 p.m.

Не реализовывал такое, так что пока не подскажу. Если будет такой опыт, то напишу статью.

ИП
  • Sept. 26, 2019, 3:25 p.m.

Как произвести загрузку используя HTTPS протокол?

F
  • Sept. 26, 2019, 7:28 p.m.
  • (edited)

точно так же как и http. Просто url адрес будет с https.

Андрей madmentat
  • Sept. 26, 2022, 9:23 p.m.
  • (edited)

Здравствуйте! Подскажите, пожалуйста, как сделать так, чтобы программа срабатыала без нажатия кнопки? Ну чисто при загрузке формы... Я так понимаю, надо что-то поменять в этой строчке

    connect(ui->pushButton, &QPushButton::clicked, downloader, &Downloader::getData);

Но вот что именно? Если не сложно, свяжитесь со мной. А то я спать спокойно не смогу пока не выясню как это делается.

Evgenii Legotckoi
  • Sept. 27, 2022, 6:41 p.m.

Попробуйте просто вызвать метод getData в конструкторе класса

g
  • Nov. 12, 2023, 9:35 p.m.

Добрый день.
Изучаю Qt на ваших уроках. Всё нормально работает на Linux. А под Win один раз запустилось, а сейчас вместо данных сайта получается ошибк "Unable to write". Куда копать, ума не приложу.
Кто подскажет, буду благдарен.

Comments

Only authorized users can post comments.
Please, Log in or Sign up
B

C++ - Test 002. Constants

  • Result:16points,
  • Rating points-10
B

C++ - Test 001. The first program and data types

  • Result:46points,
  • Rating points-6
FL

C++ - Test 006. Enumerations

  • Result:80points,
  • Rating points4
Last comments
k
kmssrFeb. 8, 2024, 6:43 p.m.
Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lesson 007. Working with ICMP Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVADec. 25, 2023, 10:30 a.m.
Boost - static linking in CMake project under Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJoDec. 25, 2023, 8:38 a.m.
Boost - static linking in CMake project under Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
GvozdikDec. 18, 2023, 9:01 p.m.
Qt/C++ - Lesson 056. Connecting the Boost library in Qt for MinGW and MSVC compilers Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Now discuss on the forum
AC
Alexandru CodreanuJan. 19, 2024, 11:57 a.m.
QML Обнулить значения SpinBox Доброго времени суток, не могу разобраться с обнулением значение SpinBox находящего в делегате. import QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: tr…
BlinCT
BlinCTDec. 27, 2023, 8:57 a.m.
Растягивать Image на парент по высоте Ну и само собою дял включения scrollbar надо чтобы был Flickable. Так что выходит как то так Flickable{ id: root anchors.fill: parent clip: true property url linkFile p…
Дмитрий
ДмитрийJan. 10, 2024, 4:18 a.m.
Qt Creator загружает всю оперативную память Проблема решена. Удалось разобраться с помощью утилиты strace. Запустил ее: strace ./qtcreator Начал выводиться весь лог работы креатора. В один момент он начал считывать фай…
Evgenii Legotckoi
Evgenii LegotckoiDec. 12, 2023, 6:48 a.m.
Побуквенное сравнение двух строк Добрый день. Там случайно не высылается этот сигнал textChanged ещё и при форматировани текста? Если решиать в лоб, то можно просто отключать сигнал/слотовое соединение внутри слота и …

Follow us in social networks