2010-12-08 133 views
7

在我的計劃,我需要下載一個文件,我碰到這篇文章就來了:下載文件Qt中從URL

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新手,所以任何提示將不勝感激。

回答

5
  • 您使用未初始化的指針,所以它指出了無處。在構造函數中初始化replyNULL
  • 創建後應該連接replyreply = manager.get(...)),而不是在構造函數中。
  • QNetworkReply從不被QNetworkManager作爲docs say刪除:

不要在連接到該信號的時隙中刪除應答的對象。使用deleteLater()。

因此,您不應該在finished插槽中調用QNetworkReply上的刪除。

  • finished插槽data0將只設置參數值設置爲0,不是你的類成員reply。這是一個不需要的代碼行。您應該將您的reply成員設置爲NULL

此外,您應該考慮在每次獲取數據塊時寫入文件,因爲在當前情況下整個文件將緩存在內存中。當指向URL的文件很大時,它可能會導致軟件的內存使用量巨大。

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次。

下面是修改的版本:

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

不過還是想到了發送錯誤報告! – 2010-12-08 03:56:11

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-> readAll())不保證一次寫入所有數據。這就是爲什麼它有一個你應該檢查的返回值,以確保一切都被寫入。如果它返回-1,則應該處理該錯誤。

    if (reply != 0) 
        delete reply; 
    

略去如果。刪除空指針是安全的。