从URL下载Qt中的文件

时间:2010-12-08 03:19:58

标签: c++ qt qt4

在我的程序中,我需要下载一个文件,我看到了这篇文章:

http://www.java2s.com/Code/Cpp/Qt/DownloadfromURL.htm

此代码确实有效,但它不适合我的程序,因此我对其进行了重新编码。我还没有完成所有这些,但我已经编码了基础知识。但是,当我测试它时,会弹出一个发送错误报告窗口。

到目前为止,这是我的代码:

QtDownload.h

#include <QObject>
#include <QString>
#include <QNetworkAccessManager>
#include <QNetworkReply>


class QtDownload : public QObject
{
    Q_OBJECT
public:
    explicit QtDownload();
    ~QtDownload();

    void setTarget(const QString& t);

private:
    QNetworkAccessManager manager;
    QNetworkReply* reply;
    QString target;
    void connectSignalsAndSlots();

signals:

public slots:
    void download();
    void downloadFinished(QNetworkReply* data);
    void downloadProgress(qint64 recieved, qint64 total);
};

QtDownload.cpp

#include "qtdownload.h"

#include <QUrl>
#include <QNetworkRequest>
#include <QFile>

QtDownload::QtDownload()
    : QObject(0)
{
    this->connectSignalsAndSlots();
}

QtDownload::~QtDownload()
{
    if (reply != 0)
        delete reply;
}

void QtDownload::connectSignalsAndSlots()
{
    QObject::connect(&manager, SIGNAL(finished(QNetworkReply*)),this, SLOT(downloadFinished(QNetworkReply*)));
    QObject::connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(downloadProgress(qint64,qint64)));
}

void QtDownload::setTarget(const QString &t)
{
    this->target = t;
}

void QtDownload::downloadFinished(QNetworkReply *data)
{
    QFile localFile("downloadedfile");
    if (!localFile.open(QIODevice::WriteOnly))
        return;
    localFile.write(data->readAll());
    localFile.close();
    delete data;
    data = 0;
}

void QtDownload::download()
{
    QUrl url = QUrl::fromEncoded(this->target.toLocal8Bit());
    QNetworkRequest request(url);
    this->reply = manager.get(request);
}

void QtDownload::downloadProgress(qint64 recieved, qint64 total)
{

}

的main.cpp

#include "qtdownload.h"
#include <QTimer>

int main()
{
    QtDownload dl;
    dl.setTarget("http://www.java2s.com/Code/Cpp/Qt/DownloadfromURL.htm");

    QTimer::singleShot(0, &dl, SLOT(download()));
}

正如我所说,它还没有完全完成,但我希望这部分在我继续前工作。

我也是Qt的新手,所以任何提示都会受到赞赏。

3 个答案:

答案 0 :(得分:5)

  • 你正在使用未初始化的指针,所以它指出无处可去。在构造函数中使用reply初始化NULL
  • 您应该在创建reply之后连接reply = manager.get(...),而不是在构造函数内部。{/ li> {li> QNetworkReply永远不会被QNetworkManager删除为docs say
  

请勿删除与此信号相连的插槽中的回复对象。使用deleteLater()。

因此,您不应在QNetworkReply广告位中的finished上致电删除。

  • finished广告位设置中data0只会将参数值设置为0,而不是您的班级成员reply。这是一段不必要的代码。您应该将reply成员设置为NULL

此外,每次获得数据块时都应考虑写入文件,因为在当前情况下整个文件将缓冲在内存中。当指向URL的文件很大时,它可能会导致软件的大量内存使用。

答案 1 :(得分:1)

您需要QCoreApplication才能启动Qt4的事件循环。 这样的事情应该有效(未经测试):

int main(int argc, char **argv) {
    QCoreApplication app(argc, argv);
    QtDownload dl;
    dl.setTarget("http://www.java2s.com/Code/Cpp/Qt/DownloadfromURL.htm");

    dl.download();
    QObject::connect(app, SIGNAL(aboutToQuit()), app, SLOT(quit()));
    return app.exec();
}

编辑::新版本

我发现了一些问题:

  1. 您不需要自定义回复,也不要在构造函数中将其设置为0,因此如果它从未使用过,它会在~QtDownload()中删除随机内存;
  2. 您正在data内删除QtDownload::downloadFinished,不应该这样做,它由Qt处理,因此会被删除两次。
  3. 因为#2,您删除了reply 3次。
  4. 以下是修改后的版本:

    qtdownload.h

    #include <QObject>
    #include <QString>
    #include <QtNetwork/QNetworkAccessManager>
    #include <QtNetwork/QNetworkReply>
    
    
    class QtDownload : public QObject {
        Q_OBJECT
    public:
        explicit QtDownload();
        ~QtDownload();
    
        void setTarget(const QString& t);
    
    private:
        QNetworkAccessManager manager;
        QString target;
    
    signals:
        void done();
    
    public slots:
        void download();
        void downloadFinished(QNetworkReply* data);
        void downloadProgress(qint64 recieved, qint64 total);
    };
    

    qtdownload.cpp

    #include "qtdownload.h"
    #include <QCoreApplication>
    #include <QUrl>
    #include <QNetworkRequest>
    #include <QFile>
    #include <QDebug>
    
    QtDownload::QtDownload() : QObject(0) {
        QObject::connect(&manager, SIGNAL(finished(QNetworkReply*)),this, SLOT(downloadFinished(QNetworkReply*)));
    }
    
    QtDownload::~QtDownload() {
    
    }
    
    
    void QtDownload::setTarget(const QString &t) {
        this->target = t;
    }
    
    void QtDownload::downloadFinished(QNetworkReply *data) {
        QFile localFile("downloadedfile");
        if (!localFile.open(QIODevice::WriteOnly))
            return;
        const QByteArray sdata = data->readAll();
        localFile.write(sdata);
        qDebug() << sdata;
        localFile.close();
    
        emit done();
    }
    
    void QtDownload::download() {
        QUrl url = QUrl::fromEncoded(this->target.toLocal8Bit());
        QNetworkRequest request(url);
        QObject::connect(manager.get(request), SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(downloadProgress(qint64,qint64)));
    
    }
    
    void QtDownload::downloadProgress(qint64 recieved, qint64 total) {
        qDebug() << recieved << total;
    }
    

    main.cpp

    #include <QtCore>
    #include "qtdownload.h"
    int main(int argc, char **argv) {
        QCoreApplication app(argc, argv);
        QtDownload dl;
        dl.setTarget("http://localhost");
    
        dl.download();
        //quit when the download is done.
        QObject::connect(&dl, SIGNAL(done()), &app, SLOT(quit()));
        return app.exec();
    }
    

答案 2 :(得分:1)

正如您所要求的,一些一般性意见:

void QtDownload::downloadFinished(QNetworkReply *data)
{
    QFile localFile("downloadedfile");
    if (!localFile.open(QIODevice::WriteOnly))
        return;
    localFile.write(data->readAll());
    localFile.close();
    delete data;
    data = 0;
}
  1. 您可以读取一个块中的所有数据。不适合大文件。更好地逐步阅读。
  2. 从插槽中删除参数数据很危险。您不知道网络管理器是否继续使用(或删除)对象“数据”在发出完成信号后指向右侧。可能你甚至不必删除回复,如果它由经理拥有,则需要检查文档。
  3. 如果打开文件失败,则不会删除数据。所以无论什么是正确的,它是不一致的。要么泄漏,要么存在双重删除的风险。
  4. localFile.write(data-&gt; readAll())无法保证一次写入所有数据。这就是为什么它有一个你应该检查的返回值,以确保所有内容都被写入。如果返回-1,则应该处理错误。

    if (reply != 0)
        delete reply;
    
  5. 省略if。删除空指针是安全的。