windows qt - 如何通过http下载和保存图像?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6285661/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 17:01:43  来源:igfitidea点击:

qt - how to download and save image via http?

c++windowsqt

提问by aaaomg

I am trying to download and save some images with Qt in a console appplication. Here is what I got so far, (all code is compiling, but after run, it seems to don't enter to replyFinished()function...)

我正在尝试在控制台应用程序中使用 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...";
}

回答by Lwin Htoo Ko

Download Image using QNetworkAccessManager

使用 QNetworkAccessManager 下载图像

header file

头文件

#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

source file

源文件

#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();
    }
}

回答by rob

This is an old question, but for reference, I'll post a working version of @lwinhtooko's code:

这是一个老问题,但作为参考,我将发布@lwinhtooko 代码的工作版本:

downloader.h:

下载器.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:

下载器.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;
}

The issue appeared to be the way QNetworkReplywas being used.

问题似乎是使用的方式QNetworkReply

回答by Darkproduct

This Question is old, but I had a similar problem and now I have a solution for Qt 5.8.

这个问题很旧,但我遇到了类似的问题,现在我有了 Qt 5.8 的解决方案。

The code is designed to work fast and the network requests are done in an asynchronous way. Therefore you have to provide an ID for each call to know which replay has finished.

该代码旨在快速运行,并且网络请求以异步方式完成。因此,您必须为每个调用提供一个 ID,以了解哪个重放已完成。

Additionally, this code uses SSL. If you don't want to use SSL encryption delete the 4 lines with QSslConfiguartion.

此外,此代码使用 SSL。如果您不想使用 SSL 加密,请使用 QSslConfiguartion 删除 4 行。

filedownloader.h:

文件下载器.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:

文件下载器.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());
}

回答by Lwin Htoo Ko

header file

头文件

#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

source file

源文件

#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());
}