Talon06
Talon06

Reputation: 1796

QT Downloading File with QNetworkAccessManager

I am trying to make the code in this question work. qt - how to download and save image via http?

It creates the files, but no data is written to them. My best guess is that the connect to the singals and slots is not working. What am I doing wrong?

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    QString getPageImage(QString url = "");
    bool saveToDisk(const QString &filename, QIODevice *data);
    ~MainWindow();

private slots:
    void on_btnDownload_clicked();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

qdownload.h

#ifndef QDOWNLOADER_H
#define QDOWNLOADER_H

#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QFile>
#include <QStringList>
#include <QDir>
#include <QDebug>

class QDownloader : public QObject
{
    Q_OBJECT
public:
    explicit QDownloader(QObject *parent = 0);
    virtual ~QDownloader();
    void setFile(QString fileURL, QString folderName, QString fileName);

private:
    QNetworkAccessManager *manager;
    QNetworkReply *reply;
    QFile *file;

private slots:
    void onDownloadProgress(qint64,qint64);
    void onFinished(QNetworkReply*);
    void onReadyRead();
    void onReplyFinished();
};

#endif // QDOWNLOADER_H

mainwindow.cpp

   #include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QNetworkAccessManager"
#include "QNetworkReply"
#include "QFile"
#include "QDebug"
#include "QUrl"
#include "QStringList"
#include "qdownloader.h"
#include <QTimer>


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->progressBar->setVisible(false);
}

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

void MainWindow::on_btnDownload_clicked()
{
    QString link = ui->txtURL->text();
    int issue = ui->sbIssue->value();
    ui->progressBar->setMaximum(issue);
    ui->progressBar->setValue(0);
    ui->progressBar->setVisible(true);
    for(int j = 1; j <= issue; j++){
        int i = 1;
        while(getPageImage(link + "/" + QString::number(j) + "/" + QString::number(i) + "/").length() > 0){
            QString filename = "http://" + getPageImage(link + "/" + QString::number(j) + "/" + QString::number(i) + "/");
            qDebug() << filename;
            QDownloader qDL;
            qDL.setFile(filename,ui->txtTitle->text() + "_" + QString::number(j),ui->txtTitle->text() + "_" + QString::number(j) + "_" + QString::number(i));
            //qDebug() << getPageImage(link + "/" + QString::number(j) + "/" + QString::number(i) + "/").length();
            i++;
        }
        ui->progressBar->setValue(j);
    }
    ui->progressBar->setVisible(false);
}


QString MainWindow::getPageImage(QString url){
    QString pic = "";
    if(url.length() > 0){
        QNetworkAccessManager manager;
        QNetworkReply *response = manager.get(QNetworkRequest(QUrl(url)));
        QEventLoop event;
        connect(response,SIGNAL(finished()),&event,SLOT(quit()));
        event.exec();
        QString html = response->readAll();

        if(html.length() > 0){
            QStringList str;
            str = html.split("\n");
            //qDebug() << url;

            for (int i = 0; i < str.size(); ++i){
                if(str.at(i).contains("id=\"mainImg\"", Qt::CaseInsensitive)){

                    pic = str.at(i);
                    pic = pic.remove(QRegExp("<img[^>]*src=['|\"]",  Qt::CaseInsensitive));
                    pic = pic.remove(QString::fromStdString("//"), Qt::CaseInsensitive);
                    pic = pic.remove('"');
                    pic = pic.remove("'");
                    pic = pic.remove('<');
                    pic = pic.remove('>');
                    pic = pic.remove(';');
                    pic = pic.left(pic.length()-1);
                    //qDebug() << str.at(i);
                    //qDebug() << pic;
                }
            }
        }else{
            pic = "";
        }
        //qDebug() << "Lines: " << str.size();

    }else{
        pic = "";
    }
    return pic;
}

qdownload.cpp

#include "qdownloader.h"

QDownloader::QDownloader(QObject *parent) :
    QObject(parent)
{
    manager = new QNetworkAccessManager;
}

QDownloader::~QDownloader()
{
    manager->deleteLater();
}

void QDownloader::setFile(QString fileURL, QString folderName, QString fileName)
{

    QDir dir;
    if(dir.exists(folderName)){
        //qDebug() << "Existis: " + folderName;
    }else{
        dir.mkdir(folderName);
        //() << "Created: " + folderName;
    }

    QString filePath = fileURL;
    QStringList filePathList = filePath.split('/');
    QString fileExt = filePathList.at(filePathList.count() - 1);
    fileExt = "jpg";
    QString saveFilePath;
    saveFilePath = QString(folderName + "/" + fileName + "." + fileExt );



    QNetworkRequest request;
    request.setUrl(QUrl(fileURL));
    reply = manager->get(request);



    file = new QFile;
    file->setFileName(saveFilePath);


    connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(onDownloadProgress(qint64,qint64)));
    connect(manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(onFinished(QNetworkReply*)));
    connect(reply,SIGNAL(readyRead()),this,SLOT(onReadyRead()));
    connect(reply,SIGNAL(finished()),this,SLOT(onReplyFinished()));
}

void QDownloader::onDownloadProgress(qint64 bytesRead,qint64 bytesTotal)
{
    qDebug(QString::number(bytesRead).toLatin1() +" - "+ QString::number(bytesTotal).toLatin1());
}

void QDownloader::onFinished(QNetworkReply * reply)
{
    switch(reply->error())
    {
        case QNetworkReply::NoError:
        {
            qDebug("file is downloaded successfully.");
        }break;
        default:{
            qDebug(reply->errorString().toLatin1());
        };
    }

    if(file->isOpen())
    {
        file->close();
        file->deleteLater();
    }
}

void QDownloader::onReadyRead()
{
    qDebug() << "Ready";
    file->open(QIODevice::WriteOnly);
    file->write(reply->readAll());
}

void QDownloader::onReplyFinished()
{
    if(file->isOpen())
    {
        file->close();
        file->deleteLater();
    }
}

Upvotes: 1

Views: 14834

Answers (1)

mhcuervo
mhcuervo

Reputation: 2660

I prepared a very basic example you can use as reference.

In some place in "my" downloader I launch the request:

QNetworkRequest request;
request.setUrl(org);
_reply = _manager->get(request); // Manager is my QNetworkAccessManager
connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)),
            this, SLOT(error(QNetworkReply::NetworkError)));
connect(_reply, SIGNAL(downloadProgress(qint64, qint64)),
            this, SLOT(updateProgress(qint64, qint64)));
connect(_reply, SIGNAL(finished()),
            this, SLOT(finished()));

As you can see all you need to do is to get() and properly use the signals of the QNetworkReply. Following "my" slots:

void MyDownloader::error(QNetworkReply::NetworkError err)
{
    // Manage error here.
    _reply->deleteLater();
}

void MyDownloader::updateProgress(qint64 read, qint64 total)
{
    // This is where you can use the progress info for, lets say, update a progress bar:
    // progressBar->setMaximum(total);
    // progressBar->setValue(read);
}

void MyDownloader::finished()
{
    // Save the image here
    QByteArray b = _reply->readAll();
    QFile file(des); // "des" is the file path to the destination file
    file.open(QIODevice::WriteOnly);
    QDataStream out(&file);
    out << b;
    _reply->deleteLater();
    // done
}

Notice that you can write to the file in updateProgress() instead of writing the whole file at once when the reply is finished.


For writing on updateProgress(), open and/or create the QFile at get time. Then use reply's readAll on every update and write the read data to the file then close the file when finished.

// ...
    _file = new QFile(des);
    _reply = _manager->get(request);
/// ...

void MyDownloader::updateProgress(qint64 read, qint64 total)
{
    QByteArray b = _reply->readAll();
    QDataStream out(_file);
    out << b;
}

void MyDownloader::finished()
{
    // Done
    _reply->deleteLater();
    _file->close();
    // probably delete the file object too
}

Upvotes: 6

Related Questions