祗疼妳一个 发表于 2024-7-16 01:29:48

Qt文件下载工具

在Qt中实现文件下载功能,通常可以通过多种方式来完成,包罗使用 QNetworkAccessManager 和 QNetworkReply 类,或者使用更高级别的 QHttpMultiPart 类。以下是两种常见的实现方法:
方法1:使用 QNetworkAccessManager 和 QNetworkReply
创建 QNetworkAccessManager 对象:这个对象负责管理和处置惩罚网络哀求。
发送 GET 哀求:使用 QNetworkAccessManager 的 get 方法来发送一个GET哀求到指定的URL。
接收数据:通过重写槽函数 readyRead 来接收数据。
生存文件:将接收到的数据写入到文件中。
处置惩罚完成:当下载完成后,重写 finished 槽函数来处置惩罚完成的逻辑。
https://i-blog.csdnimg.cn/direct/1e9b6a4f1769495cb018ea04416cee5b.gif

#ifndef DOWNLOAD_DIALOG_H
#define DOWNLOAD_DIALOG_H

#include <QDir>
#include <QDialog>
#include <ui_Downloader.h>

namespace Ui {
class Downloader;
}

class QNetworkReply;
class QNetworkAccessManager;

/**
* \brief Implements an integrated file downloader with a nice UI
*/
class Downloader : public QWidget
{
    Q_OBJECT

signals:
    void downloadFinished (const QString& url, const QString& filepath);

public:
    explicit Downloader (QWidget* parent = 0);
    ~Downloader();

    bool useCustomInstallProcedures() const;

    QString downloadDir() const;
    void setDownloadDir(const QString& downloadDir);

public slots:
    void setUrlId (const QString& url);
    void startDownload (const QUrl& url);
    void setFileName (const QString& file);
    void setUserAgentString (const QString& agent);
    void setUseCustomInstallProcedures (const bool custom);

private slots:
    void finished();
    void openDownload();
    void installUpdate();
    void cancelDownload();
    void saveFile (qint64 received, qint64 total);
    void calculateSizes (qint64 received, qint64 total);
    void updateProgress (qint64 received, qint64 total);
    void calculateTimeRemaining (qint64 received, qint64 total);

private:
    qreal round (const qreal& input);

private:
    QString m_url;
    uint m_startTime;
    QDir m_downloadDir;
    QString m_fileName;
    Ui::Downloader* m_ui;
    QNetworkReply* m_reply;
    QString m_userAgentString;
    bool m_useCustomProcedures;
    QNetworkAccessManager* m_manager;
};

#endif

#pragma execution_character_set("utf-8")
#include <QDir>
#include <QFile>
#include <QProcess>
#include <QMessageBox>
#include <QNetworkReply>
#include <QDesktopServices>
#include <QNetworkAccessManager>

#include <math.h>

#include "Downloader.h"

static const QString PARTIAL_DOWN (".part");

Downloader::Downloader (QWidget* parent) : QWidget (parent)
{
    m_ui = new Ui::Downloader;
    m_ui->setupUi (this);
    /* Initialize private members */
    m_manager = new QNetworkAccessManager();

    /* Initialize internal values */
    m_url = "";
    m_fileName = "";
    m_startTime = 0;
    m_useCustomProcedures = false;

    /* Set download directory */
    m_downloadDir = QDir::homePath() + "/Downloads/";
    /* Configure the appearance and behavior of the buttons */
    m_ui->openButton->setEnabled (false);
    m_ui->openButton->setVisible (false);
    connect (m_ui->stopButton, SIGNAL (clicked()),
             this,               SLOT (cancelDownload()));
    connect (m_ui->openButton, SIGNAL (clicked()),
             this,               SLOT (installUpdate()));

    /* Resize to fit */
}

Downloader::~Downloader()
{
    delete m_ui;
    delete m_reply;
    delete m_manager;
}

/**
* Returns \c true if the updater shall not intervene when the download has
* finished (you can use the \c QSimpleUpdater signals to know when the
* download is completed).
*/
bool Downloader::useCustomInstallProcedures() const
{
    return m_useCustomProcedures;
}

/**
* Changes the URL, which is used to indentify the downloader dialog
* with an \c Updater instance
*
* \note the \a url parameter is not the download URL, it is the URL of
*       the AppCast file
*/
void Downloader::setUrlId (const QString& url)
{
    m_url = url;
}

/**
* Begins downloading the file at the given \a url
*/
void Downloader::startDownload (const QUrl& url)
{
    /* Reset UI */
    m_ui->progressBar->setValue (0);
    m_ui->stopButton->setText (tr ("Stop"));
    m_ui->downloadLabel->setText (tr ("Downloading updates"));
    m_ui->timeLabel->setText (tr ("Time remaining") + ": " + tr ("unknown"));

    /* Configure the network request */
    QNetworkRequest request (url);
    if (!m_userAgentString.isEmpty())
      request.setRawHeader ("User-Agent", m_userAgentString.toUtf8());

    /* Start download */
    m_reply = m_manager->get (request);
    m_startTime = QDateTime::currentDateTime().toTime_t();

    /* Ensure that downloads directory exists */
    if (!m_downloadDir.exists())
      m_downloadDir.mkpath (".");

    /* Remove old downloads */
    QFile::remove (m_downloadDir.filePath (m_fileName));
    QFile::remove (m_downloadDir.filePath (m_fileName + PARTIAL_DOWN));

    /* Update UI when download progress changes or download finishes */
    connect (m_reply, SIGNAL (downloadProgress (qint64, qint64)),
             this,      SLOT (updateProgress   (qint64, qint64)));
    connect (m_reply, SIGNAL (finished ()),
             this,      SLOT (finished ()));
    connect (m_reply, SIGNAL (redirected       (QUrl)),
             this,      SLOT (startDownload    (QUrl)));

}

/**
* Changes the name of the downloaded file
*/
void Downloader::setFileName (const QString& file)
{
    m_fileName = file;

    if (m_fileName.isEmpty())
      m_fileName = "QSU_Update.bin";
}

/**
* Changes the user-agent string used to communicate with the remote HTTP server
*/
void Downloader::setUserAgentString (const QString& agent)
{
    m_userAgentString = agent;
}

void Downloader::finished()
{
    /* Rename file */
    QFile::rename (m_downloadDir.filePath (m_fileName + PARTIAL_DOWN),
                   m_downloadDir.filePath (m_fileName));

    /* Notify application */
    emit downloadFinished (m_url, m_downloadDir.filePath (m_fileName));

    /* Install the update */
    m_reply->close();
    installUpdate();
    setVisible (false);
}

/**
* Opens the downloaded file.
* \note If the downloaded file is not found, then the function will alert the
*       user about the error.
*/
void Downloader::openDownload()
{
    if (!m_fileName.isEmpty())
      QDesktopServices::openUrl (QUrl::fromLocalFile (m_downloadDir.filePath (
                                                            m_fileName)));

    else {
      QMessageBox::critical (this,
                               tr ("Error"),
                               tr ("Cannot find downloaded update!"),
                               QMessageBox::Close);
    }
}

/**
* Instructs the OS to open the downloaded file.
*
* \note If \c useCustomInstallProcedures() returns \c true, the function will
*       not instruct the OS to open the downloaded file. You can use the
*       signals fired by the \c QSimpleUpdater to install the update with your
*       own implementations/code.
*/
void Downloader::installUpdate()
{
    if (useCustomInstallProcedures())
      return;

    /* Update labels */
    m_ui->stopButton->setText    (tr ("Close"));
    m_ui->downloadLabel->setText (tr ("Download complete!"));
    m_ui->timeLabel->setText   (tr ("The installer will open separately")
                                  + "...");

    /* Ask the user to install the download */
    QMessageBox box;
    box.setIcon (QMessageBox::Question);
    box.setDefaultButton   (QMessageBox::Ok);
    box.setStandardButtons (QMessageBox::Ok | QMessageBox::Cancel);
    box.setInformativeText (tr ("Click \"OK\" to begin installing the update"));
    box.setText ("<h3>" +
               tr ("In order to install the update, you may need to "
                     "quit the application.")
               + "</h3>");

    /* User wants to install the download */
    if (box.exec() == QMessageBox::Ok) {
      if (!useCustomInstallProcedures())
            openDownload();
    }

    /* Wait */
    else {
      m_ui->openButton->setEnabled (true);
      m_ui->openButton->setVisible (true);
      m_ui->timeLabel->setText (tr ("Click the \"Open\" button to "
                                    "apply the update"));
    }
}

/**
* Prompts the user if he/she wants to cancel the download and cancels the
* download if the user agrees to do that.
*/
void Downloader::cancelDownload()
{
    if (!m_reply->isFinished()) {
      QMessageBox box;
      box.setWindowTitle (tr ("Updater"));
      box.setIcon (QMessageBox::Question);
      box.setStandardButtons (QMessageBox::Yes | QMessageBox::No);
      box.setText (tr ("Are you sure you want to cancel the download?"));

      if (box.exec() == QMessageBox::Yes) {
            m_reply->abort();
      }
    }
}

/**
* Writes the downloaded data to the disk
*/
void Downloader::saveFile (qint64 received, qint64 total)
{
    Q_UNUSED(received);
    Q_UNUSED(total);

    /* Check if we need to redirect */
    QUrl url = m_reply->attribute (
                QNetworkRequest::RedirectionTargetAttribute).toUrl();
    if (!url.isEmpty()) {
      startDownload (url);
      return;
    }

    /* Save downloaded data to disk */
    QFile file (m_downloadDir.filePath (m_fileName + PARTIAL_DOWN));
    if (file.open (QIODevice::WriteOnly | QIODevice::Append)) {
      file.write (m_reply->readAll());
      file.close();
    }
}


/**
* Calculates the appropiate size units (bytes, KB or MB) for the received
* data and the total download size. Then, this function proceeds to update the
* dialog controls/UI.
*/
void Downloader::calculateSizes (qint64 received, qint64 total)
{
    QString totalSize;
    QString receivedSize;

    if (total < 1024)
      totalSize = tr ("%1 bytes").arg (total);

    else if (total < 1048576)
      totalSize = tr ("%1 KB").arg (round (total / 1024));

    else
      totalSize = tr ("%1 MB").arg (round (total / 1048576));

    if (received < 1024)
      receivedSize = tr ("%1 bytes").arg (received);

    else if (received < 1048576)
      receivedSize = tr ("%1 KB").arg (received / 1024);

    else
      receivedSize = tr ("%1 MB").arg (received / 1048576);

    m_ui->downloadLabel->setText (tr ("Downloading updates")
                                  + " (" + receivedSize + " " + tr ("of")
                                  + " " + totalSize + ")");
}

/**
* Uses the \a received and \a total parameters to get the download progress
* and update the progressbar value on the dialog.
*/
void Downloader::updateProgress (qint64 received, qint64 total)
{
    if (total > 0) {
      m_ui->progressBar->setMinimum (0);
      m_ui->progressBar->setMaximum (100);
      m_ui->progressBar->setValue ((received * 100) / total);

      calculateSizes (received, total);
      calculateTimeRemaining (received, total);
      saveFile (received, total);
    }

    else {
      m_ui->progressBar->setMinimum (0);
      m_ui->progressBar->setMaximum (0);
      m_ui->progressBar->setValue (-1);
      m_ui->downloadLabel->setText (tr ("Downloading Updates") + "...");
      m_ui->timeLabel->setText (QString ("%1: %2")
                                  .arg (tr ("Time Remaining"))
                                  .arg (tr ("Unknown")));
    }
}

/**
* Uses two time samples (from the current time and a previous sample) to
* calculate how many bytes have been downloaded.
*
* Then, this function proceeds to calculate the appropiate units of time
* (hours, minutes or seconds) and constructs a user-friendly string, which
* is displayed in the dialog.
*/
void Downloader::calculateTimeRemaining (qint64 received, qint64 total)
{
    uint difference = QDateTime::currentDateTime().toTime_t() - m_startTime;

    if (difference > 0) {
      QString timeString;
      qreal timeRemaining = total / (received / difference);

      if (timeRemaining > 7200) {
            timeRemaining /= 3600;
            int hours = int (timeRemaining + 0.5);

            if (hours > 1)
                timeString = tr ("about %1 hours").arg (hours);
            else
                timeString = tr ("about one hour");
      }

      else if (timeRemaining > 60) {
            timeRemaining /= 60;
            int minutes = int (timeRemaining + 0.5);

            if (minutes > 1)
                timeString = tr ("%1 minutes").arg (minutes);
            else
                timeString = tr ("1 minute");
      }

      else if (timeRemaining <= 60) {
            int seconds = int (timeRemaining + 0.5);

            if (seconds > 1)
                timeString = tr ("%1 seconds").arg (seconds);
            else
                timeString = tr ("1 second");
      }

      m_ui->timeLabel->setText (tr ("Time remaining") + ": " + timeString);
    }
}

/**
* Rounds the given \a input to two decimal places
*/
qreal Downloader::round (const qreal& input)
{
    return roundf (input * 100) / 100;
}

QString Downloader::downloadDir() const
{
    return m_downloadDir.absolutePath();
}

void Downloader::setDownloadDir(const QString& downloadDir)
{
    if(m_downloadDir.absolutePath() != downloadDir) {
      m_downloadDir = downloadDir;
    }
}

/**
* If the \a custom parameter is set to \c true, then the \c Downloader will not
* attempt to open the downloaded file.
*
* Use the signals fired by the \c QSimpleUpdater to implement your own install
* procedures.
*/
void Downloader::setUseCustomInstallProcedures (const bool custom)
{
    m_useCustomProcedures = custom;
}


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: Qt文件下载工具