Quick Tip: Download a File in Qt

Someone asked me a while back how to simply download a file in Qt. I mean, Qt is so mature and so extensive that you think something like this would be one function call away–wrong. It actually takes a whole class to do it right! The idea is basically that you want to get a QNetworkRequest going for your URL in a reply, and from there it’s basics. I’m going to keep the explanations quick, since this is a quick tip, and just post mainly the bare-bones code for this.

Note that this is some code taken from a past QML project of mine, so note the “Handler” in the class name and the affluent use of signals/slots for everything.

class DownloadFileHandler : public QObject

    DownloadFileHandler(const QUrl &downloadUrl, const QDir &storageLocation,
                        bool startImmediately = false);

    DownloadFileHandler() : QObject() {}

    inline void setFile(QFile *file) { pFile = file; }
    inline void setStorageLocation(const QDir &location) { mStorageLocation = location; }
    inline void setDownloadURL(const QUrl &url) { mDownloadUrl = url; }

    inline QFile* file() const { return pFile; }
    inline QDir storageLocation() const { return mStorageLocation; }
    inline QUrl downloadUrl() const { return mDownloadUrl; }

    void fileAlreadyExistsError(QString existingFileDisplayName);
    void fileOpeningError(QString errorMessage);
    void fileDownloadError(QString errorMessage);
    void fileDownloadStarted();
    void fileDownloadCancelled();
    void fileDownloadFinished();

public slots:
    void setDownloadURLSlot(const QString &url);

    void beginDownload();
    void cancelDownload();
    void downloadFinished();
    void downloadReadyRead();

    QFile *pFile;
    QDir mStorageLocation;

    QUrl mDownloadUrl;

    QNetworkReply *pNetworkReply;
    QNetworkAccessManager mNetworkManager;

Oh, get over those inlined getters/setters. I hear Qt Creator 2.8 is getting some handy-dandy refactoring tools for C++ 😉 Now lets break the implementation down.

DownloadFileHandler::DownloadFileHandler(const QUrl &downloadUrl, const QDir &storageLocation, bool startImmediately)
: QObject(), mDownloadUrl(downloadUrl), mStorageLocation(storageLocation)
// Start the download process immediately, rather than waiting for a call
if (startImmediately)

void DownloadFileHandler::beginDownload()
// Make our strings for the File
QString downloadFileName = QFileInfo(mDownloadUrl.path()).fileName();
qDebug() << "Downloading file with file name: " << downloadFileName;

QString absoluteFileAddress = mStorageLocation.path() + "/" + downloadFileName; // e.g. file name appended to the directory
qDebug() << "Downloaded file will be stored at: " << absoluteFileAddress;

pFile = new QFile(absoluteFileAddress);
qDebug() << "File being downloaded to: " + absoluteFileAddress;

// Check if we have the file open for writing
if (!pFile->open(QIODevice::WriteOnly))
// Send our message to the application
emit fileOpeningError(pFile->errorString());

// Delete file
if (pFile)
delete pFile;
pFile = NULL;

return; // Break, failed

// Get the data from our request on the URL
pNetworkReply = mNetworkManager.get(QNetworkRequest(mDownloadUrl));
emit fileDownloadStarted();

// Setup signals/slots
connect(pNetworkReply, SIGNAL(finished()), this, SLOT(downloadFinished()));
connect(pNetworkReply, SIGNAL(readyRead()), this, SLOT(downloadReadyRead()));

void DownloadFileHandler::cancelDownload()
emit fileDownloadCancelled();

void DownloadFileHandler::downloadFinished()
// Make sure everything is written before we continue

// If there was an error, emit it so we can handle it and/or log it
if (pNetworkReply->error())
emit fileDownloadError(pNetworkReply->errorString());

pNetworkReply->deleteLater(); // Very important that we use deleteLater()!
pNetworkReply = NULL;

delete pFile;
pFile = NULL;

// Tell the application we are done
emit fileDownloadFinished();

void DownloadFileHandler::downloadReadyRead()
// If pFile exists, dump all reply data to disk to save memory
if (pFile)

void DownloadFileHandler::setDownloadURLSlot(const QString &url)

Under 100 lines 😀 This is really a quick tip, so I won’t do as much explaining as normally. Basically, take a look at line 38. The idea behind the Network Access Manager is that you have requests and replies from those requests. We put in a request for the file and get a reply back. We can then query the reply for things like data, progress, etc. Perhaps we can add a progress bar in the future!

I hope you enjoyed the quick tip. Keep on coding!


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s