QT - как скачать и сохранить изображение через http? - PullRequest
3 голосов
/ 09 июня 2011

Я пытаюсь загрузить и сохранить некоторые изображения с помощью Qt в приложении консоли. Вот что я получил до сих пор (весь код компилируется, но после запуска кажется, что он не входит в replyFinished() функцию ...)

void Test::start()
{
    std::cout << "start1";
    QNetworkAccessManager *manager = new QNetworkAccessManager();
    connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
    manager->get(QNetworkRequest(QUrl("http://www.exylum.mydevil.net/firefox.jpg")));
}

void Test::replyFinished(QNetworkReply* reply)
{
    std::cout << "st";
    QImage* img2 = new QImage();
    img2->loadFromData(reply->readAll());

    if(img2->isNull())
        std::cout << "oops";

    if(img2->save("omg2.jpg", "JPG"))
        std::cout << "saved";
    else
        std::cout << "dont...";
}

Ответы [ 4 ]

4 голосов
/ 14 июня 2011

Загрузить изображение с помощью QNetworkAccessManager

заголовочный файл

#ifndef QDOWNLOADER_H
#define QDOWNLOADER_H

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

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

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

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

#endif // QDOWNLOADER_H

исходный файл

#include "qdownloader.h"

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

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

void QDownloader::setFile(QString fileURL)
{
    QString filePath = fileURL;
    QString saveFilePath;
    QStringList filePathList = filePath.split('/');
    QString fileName = filePathList.at(filePathList.count() - 1);
    saveFilePath = QString("C:/Images/" + fileName );

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

    file = new QFile;
    file->setFileName(saveFilePath);
    file->open(QIODevice::WriteOnly);

    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()
{
    file->write(reply->readAll());
}

void QDownloader::onReplyFinished()
{
    if(file->isOpen())
    {
        file->close();
        file->deleteLater();
    }
}
0 голосов
/ 02 мая 2018

Этот вопрос старый, но у меня была похожая проблема, и теперь у меня есть решение для Qt 5.8.

Код предназначен для быстрой работы, а сетевые запросы выполняются асинхронно. Поэтому вам необходимо указывать идентификатор для каждого вызова, чтобы узнать, какое воспроизведение завершено.

Кроме того, этот код использует SSL. Если вы не хотите использовать шифрование SSL, удалите 4 строки с помощью QSslConfiguartion.

filedownloader.h:

#ifndef FILEDOWNLOADER_H
#define FILEDOWNLOADER_H

#include <QObject>
#include <QStringList>
#include <QFile>
#include <QDir>

#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>

class FileDownloader : public QObject
{
    Q_OBJECT

public:
    explicit FileDownloader(QObject *parent = 0);
    virtual ~FileDownloader();
    void downloadFile(QUrl url, QString id, QString dir_absolute_path);

signals:
    // emits error string
    void error(QString);
    // Emits path to img on disk and id
    void downloaded(QString, QString);

private slots:
    void fileDownloaded();
    void onReadyRead();

private:
    QNetworkAccessManager *webCtrl;
    QMap<QNetworkReply*, QFile*> replytofile;
    QMap<QNetworkReply*, QPair<QString, QString> > replytopathid;

    const QByteArray userAgent = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36";
};

#endif // FILEDOWNLOADER_H

filedownloader.cpp:

#include "filedownloader.h"
#include <QDebug>

FileDownloader::FileDownloader(QObject *parent) :
    QObject(parent),
    webCtrl(new QNetworkAccessManager(this))
{

}

FileDownloader::~FileDownloader() 
{
    delete webCtrl;
}

void FileDownloader::downloadFile(QUrl url, QString id, QString dir_absolute_path)
{
    QString url_string = url.toString();
    QString path = dir_absolute_path + url_string.right(url_string.size() - url_string.lastIndexOf("/"));

    QFile *file = new QFile(path, this);
    if(!file->open(QIODevice::WriteOnly))
    {
        return;
    }

    QNetworkRequest request(url);
    request.setRawHeader("User-Agent", userAgent);

    QSslConfiguration sslConfiguration(QSslConfiguration::defaultConfiguration());
    sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
    sslConfiguration.setProtocol(QSsl::AnyProtocol);
    request.setSslConfiguration(sslConfiguration);

    QNetworkReply *reply = webCtrl->get(request);
    replytofile.insert(reply, file);
    replytopathid.insert(reply, QPair<QString, QString>(path, id));

    QObject::connect(reply, &QNetworkReply::finished, this, &FileDownloader::fileDownloaded);
    QObject::connect(reply, &QNetworkReply::readyRead, this, &FileDownloader::onReadyRead);
}

void FileDownloader::fileDownloaded()
{
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());

    if (replytofile[reply]->isOpen())
    {
        replytofile[reply]->close();
        replytofile[reply]->deleteLater();
    }

    switch(reply->error())
    {
    case QNetworkReply::NoError:
        break;

    default:
        emit error(reply->errorString().toLatin1());
        break;
    }

    emit downloaded(replytopathid[reply].first, replytopathid[reply].second);

    replytofile.remove(reply);
    replytopathid.remove(reply);
    delete reply;
}

void FileDownloader::onReadyRead()
{
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());

    replytofile[reply]->write(reply->readAll());
}
0 голосов
/ 11 сентября 2015

Это старый вопрос, но для справки я выложу рабочую версию кода @ lwinhtooko:

downloader.h:

#pragma once

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

class Downloader : public QObject {
    Q_OBJECT
    QFile *m_file;
    bool m_isReady = true;

public:
    explicit Downloader(QObject *parent = 0) : QObject(parent) {}
    virtual ~Downloader() { delete m_file; }

    void downloadFileFromURL(const QString &url, const QString &filePath);

private slots:
    void onDownloadFileComplete(QNetworkReply *reply);
};

downloader.cpp:

#include "downloader.h"

void Downloader::downloadFileFromURL(const QString &url, const QString &filePath) {
    if (!m_isReady)
        return;
    m_isReady = false;

    const QString fileName = filePath + url.right(url.size() - url.lastIndexOf("/")); // your filePath should end with a forward slash "/"
    m_file = new QFile();
    m_file->setFileName(fileName);
    m_file->open(QIODevice::WriteOnly);
    if (!m_file->isOpen()) {
        m_isReady = true;
        return; // TODO: permission check?
    }

    QNetworkAccessManager *manager = new QNetworkAccessManager;

    QNetworkRequest request;
    request.setUrl(QUrl(url));

    connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(onDownloadFileComplete(QNetworkReply *)));

    manager->get(request);
}

void Downloader::onDownloadFileComplete(QNetworkReply *reply) {
    if (!m_file->isWritable()) {
        m_isReady = true;
        return; // TODO: error check
    }

    m_file->write(reply->readAll());
    m_file->close(); // TODO: delete the file from the system later on
    m_isReady = true;
}

Проблема, похоже, заключалась в использовании QNetworkReply.

0 голосов
/ 09 июня 2011

заголовочный файл

#ifndef IMAGEDOWNLOAD_H
#define IMAGEDOWNLOAD_H

#include <QWidget>
#include <QHttp>
#include <QFile>
#include <QUrl>

class ImageDownload : public QWidget
{
    Q_OBJECT
public:
    explicit ImageDownload(QWidget *parent = 0);

private:
    int httpGetId;
    QHttp http;
    QFile myfile;

private slots:
    void httpRequestFinished(int, bool);
    void progress(int,int);
};

#endif // IMAGEDOWNLOAD_H

исходный файл

#include "imagedownload.h"

ImageDownload::ImageDownload(QWidget *parent) :
    QWidget(parent)
{
    QUrl url("url of image.");

    myfile.setFileName("C:/Qt/imagefilename");
    myfile.open(QIODevice::WriteOnly);

    connect(&http,SIGNAL(requestFinished(int,bool)),this,SLOT(httpRequestFinished(int,bool)));
    connect(&http,SIGNAL(dataReadProgress(int,int)),this,SLOT(progress(int,int)));
    http.setHost(url.host(),QHttp::ConnectionModeHttp,url.port());
    httpGetId = http.get(url.path(),&myfile);
}

void ImageDownload::httpRequestFinished(int id, bool error)
{
    if(id == httpGetId)
    {
        myfile.close();
    }
    if(error)
    {
        qDebug(http.errorString().toLatin1());
    }
}

void ImageDownload::progress(int a, int b)
{
    qDebug(QString::number(a).toLatin1()+" : "+QString::number(b).toLatin1());
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...