2010-12-08 12 views
7

En mi programa tengo que descargar un archivo, y me encontré con este artículo:la descarga de archivos en Qt desde URL

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

Este código de trabajo, pero no encaja en mi programa, así que volvió a codificarlo No lo he completado todo, pero tengo los conceptos básicos codificados. Sin embargo, cuando lo pruebo, aparece con una ventana de enviar informe de errores.

Hasta ahora, este es mi código:

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

Como ya he dicho que no es completamente terminado pero yo wa Esta parte debe estar funcionando antes de continuar.

También soy nuevo en Qt, así que cualquier consejo sería apreciado.

Respuesta

5
  • Estás usando puntero no inicializado, por lo que señala a ninguna parte. Inicialice reply con NULL en su constructor.
  • Debe conectar reply después de haber sido creado (reply = manager.get(...)), no dentro de su constructor.
  • QNetworkReply no se suprime por QNetworkManager como docs say:

no elimine el objeto respuesta en la ranura conectada a esta señal. Use deleteLater().

Por lo tanto, no debe llamar a eliminar en QNetworkReply en finished ranura.

  • En finished establecer el valor del parámetro data a 0 sólo se configurará a 0 ranura, no su miembro de la clase reply. Es una línea de código innecesaria. En su lugar, debe configurar su miembro reply en NULL.

También debería considerar escribir en un archivo cada vez que obtiene fragmentos de datos, ya que todo el archivo se almacenará en la memoria en su caso actual. Puede llevar a un gran uso de memoria de su software cuando el archivo en la URL señalada es grande.

1

Necesita QCoreApplication para iniciar el ciclo de eventos para Qt4. Algo como esto debería funcionar (no probado):

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

edición :: nueva versión

he encontrado algunos problemas:

  1. No necesita la respuesta personalizada, también nunca establézcalo en 0 en su constructor, por lo que si nunca se utilizó, eliminará una porción aleatoria de memoria en su ~ QtDownload();
  2. estaba borrando data dentro de QtDownload::downloadFinished, lo que no debe hacerse, es manejado por Qt, por lo que fue eliminado dos veces.
  3. debido al # 2, borró reply 3 veces.

Aquí está la versión modificada:

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

¡No obstante, aparece el informe de error de envío! –

+0

Se corrigió el código. – OneOfOne

+0

Lo siento, hay muchos errores en su respuesta –

1

A medida que preguntó por él, algunos comentarios generales:

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. de leer todos los datos en un solo trozo. Malo para grandes archivos. Mejor leerlo de manera incremental.
  2. Eliminar los datos del argumento de una ranura es peligroso. No se sabe si el administrador de red continúa utilizando (o eliminando) los puntos de "datos" del objeto justo después de que emite la señal finalizada. Probablemente ni siquiera tenga que eliminar la respuesta, si es propiedad del administrador, algo para verificar la documentación.
  3. Si falla la apertura de los archivos, los datos no se eliminan. Entonces, lo que sea correcto, es inconsistente. O bien tiene una fuga o corre el riesgo de una eliminación doble.
  4. localFile.write (data-> readAll()) no se garantiza que escriba todos los datos a la vez. es por eso que tiene un valor de retorno, que debe verificar, para asegurarse de que todo está escrito. Si devuelve -1, debe manejar el error.

    if (reply != 0) 
        delete reply; 
    

omitir el caso. Eliminar un puntero nulo es seguro.

Cuestiones relacionadas