在Qt中实现文件下载功能,通常可以通过多种方式来完成,包罗使用 QNetworkAccessManager 和 QNetworkReply 类,或者使用更高级别的 QHttpMultiPart 类。以下是两种常见的实现方法:
方法1:使用 QNetworkAccessManager 和 QNetworkReply
创建 QNetworkAccessManager 对象:这个对象负责管理和处置惩罚网络哀求。
发送 GET 哀求:使用 QNetworkAccessManager 的 get 方法来发送一个GET哀求到指定的URL。
接收数据:通过重写槽函数 readyRead 来接收数据。
生存文件:将接收到的数据写入到文件中。
处置惩罚完成:当下载完成后,重写 finished 槽函数来处置惩罚完成的逻辑。
- #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企服之家,中国第一个企服评测及商务社交产业平台。 |