详细流程可参考本博客:https://blog.csdn.net/weixin_38739598/article/details/106571074
CHttpDownLoadFile头文件
#pragma once
#include <QWidget>
//网络相关头文件
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
//文件相关头文件
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QDesktopServices>
class CHttpDownLoadFile : public QWidget
{
Q_OBJECT
public:
CHttpDownLoadFile(const QString &url, const QString &fileName, const QString &dir,QWidget *parent);
~CHttpDownLoadFile();
void DownLoadFile();
void DestroyData();
signals:
//文件下载结束
void DownloadFinishedSignal();
//文件下载进度
void DownloadProcess(QString, qint64, qint64);
public slots:
void ReplyNewDataArrived();//响应m_netReply有新的数据到达
void ReplyFinished();//响应数据接收完成
void ReplyDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); //响应文件下载进度
public:
QNetworkAccessManager *m_netAccessManager;//网络参数
QNetworkReply *m_netReply;
QUrl m_urlAdress;//网络地址
QString m_strFileName;//需要下载的文件名
QString m_strDir;//文件的存储位置
QFile *m_file;//下载的文件
qint64 m_nReceived;//下载文件时,已经接收的文件大小和总共大小
qint64 m_nTotal;
bool m_bIsFinished;
};
CHttpDownLoadFile源文件
#include "CHttpDownLoadFile.h"
CHttpDownLoadFile::CHttpDownLoadFile(const QString &url, const QString &fileName, const QString &dir, QWidget *parent)
: QWidget(parent),
m_urlAdress(url),
m_strFileName(fileName),
m_strDir(dir),
m_bIsFinished(false)
{
m_netAccessManager = new QNetworkAccessManager(this);
}
CHttpDownLoadFile::~CHttpDownLoadFile()
{
}
void CHttpDownLoadFile::DownLoadFile()
{
m_bIsFinished = false;
QNetworkRequest request(m_urlAdress);
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
m_netReply = m_netAccessManager->get(request);
connect(m_netReply, SIGNAL(readyRead()), this, SLOT(ReplyNewDataArrived()));//当有新数据到达时就会触发此信号
connect(m_netReply, SIGNAL(finished()), this, SLOT(ReplyFinished()));//完成数据接收后发送此信号
connect(m_netReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(ReplyError(QNetworkReply::NetworkError)));//出现错误时发送此信号;
connect(m_netReply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(ReplyDownloadProgress(qint64, qint64)));//用来提示文件下载进度
if (m_strFileName.isEmpty())//文件名
{
QFileInfo fileInfo(m_urlAdress.path());
m_strFileName = fileInfo.fileName();
}
if (!m_strDir.isEmpty())//文件夹
{
QDir directory(m_strDir);
if (!directory.exists())//没有此文件夹,则创建
{
directory.mkpath(m_strDir);
}
m_strFileName = m_strDir + m_strFileName;//添加/是为了防止用户名没有加/,因为对于文件夹来说两个/都会当成一个/
}
if (QFile::exists(m_strFileName))//如果文件已经存在,那么删除
{
QFile::remove(m_strFileName);
}
m_file = new QFile(m_strFileName);
if (!m_file->open(QIODevice::WriteOnly | QIODevice::Text))
{
m_file->close();
delete m_file;
m_file = NULL;
return;
}
}
void CHttpDownLoadFile::DestroyData()
{
m_netAccessManager->deleteLater();
m_netReply->deleteLater();
m_file->close();
m_file->deleteLater();
}
void CHttpDownLoadFile::ReplyNewDataArrived()//响应m_netReply有新的数据到达
{
if (m_file)
{
// 写文件-形式为追加
QFile file(m_strFileName);
if (file.open(QIODevice::Append))
file.write(m_netReply->readAll());
file.close();
}
else
{
qDebug() << m_netReply->readAll();
}
}
void CHttpDownLoadFile::ReplyFinished()//响应数据接收完成
{
m_bIsFinished = true;
m_netAccessManager->deleteLater();
m_netReply->deleteLater();
m_file->close();
m_file->deleteLater();
emit DownloadFinishedSignal();
}
void CHttpDownLoadFile::ReplyDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
QFileInfo fileInfo(m_urlAdress.path());
QString strFileName = fileInfo.fileName();
emit DownloadProcess(strFileName, bytesReceived, bytesTotal);
}
AutoUpdate 头文件
#pragma once
#include <QtWidgets/QDialog>
#include <QtWidgets/QMainWindow>
#include <QUrl>
#include <QDesktopServices>
//网络相关头文件
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
//JSON相关头文件
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QMessageBox>
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QTime>
#include <QProgressBar>
#include <QTextCodec>
#include <QProcess>
#include "zlib.h"
#include "zconf.h"
#include "unzip.h"
#include <direct.h>
#include "ui_AutoUpdate.h"
#include "CHttpDownLoadFile.h"
#include <QList>
class AutoUpdate : public QDialog
{
Q_OBJECT
public:
AutoUpdate(QWidget *parent = Q_NULLPTR);
private:
int ParseJson(const QString &str); //解析数据函数的声明
private:
QNetworkAccessManager * m_NetManager; //定义网络请求对象
QNetworkAccessManager * m_NetManagerDown; //定义网络请求对象
QNetworkReply * m_pReply;
QString m_CurVerison; //定义当前软件的版本号
QUrl m_url;
QString m_strUrl;
QString m_strFileName;
QTime m_downloadTime;
int m_nTime;
QString m_lastVerison;
private:
CHttpDownLoadFile *m_httpXML;
QList<QString> m_listFileDir;
QList<QString> m_listFileName;
QString m_strTip;
QString m_strXmlName;
void DownLoadXML();
QString GetElementVersion(const QString &xml, const QString &name);
bool CheckVersion(const QString &v1, const QString &v2);
int CheckUpdateFiles(const QString &xml1, const QString &xml2);
void DownLoadUpdateFiles();
void ExitApp(const QString &name);
private slots:
void slotUpdateNow();
void slotClose();
void replyFinished(QNetworkReply *reply); //json 文件下载结束
void onDownloadProgress(QString fileName, qint64 bytesReceived, qint64 bytesTotal); //下载进度
void ReplyHttpFinished();
private:
Ui::AutoUpdate ui;
};
AutoUpdate源文件
# include <stdio.h>
# include <inttypes.h>
# include <Windows.h>
# include <WinInet.h>
#include "AutoUpdate.h"
#include "configer.h"
#include "Format.h"
#include <QDomDocument>
AutoUpdate::AutoUpdate(QWidget *parent)
: QDialog(parent),
m_NetManager(NULL),
m_NetManagerDown(NULL),
m_nTime(0)
{
ui.setupUi(this);
ui.progressBar->setValue(0);
m_strFileName = QString(QString::fromLocal8Bit(Configer::GetInstance()->FilePath().c_str())) + "\\Test.zip";
m_CurVerison = QString::fromStdString(Configer::GetInstance()->GetVersion());
setWindowIcon(QIcon(QString::fromStdString(Configer::GetInstance()->GetWindowIcon())));
setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint | Qt::WindowStaysOnTopHint);
m_NetManager = new QNetworkAccessManager(this); //新建QNetworkAccessManager对象
connect(m_NetManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));//关联信号和槽
QNetworkRequest quest;
quest.setUrl(QUrl(Configer::GetInstance()->GetCfgQurl().c_str())); //包含最新版本软件的下载地址
//quest.setHeader(QNetworkRequest::UserAgentHeader, "RT-Thread ART");
QNetworkReply *reply = m_NetManager->get(quest); //发送get网络请求
connect(reply, SIGNAL(error), this, SLOT(slotError));
}
int AutoUpdate::ParseJson(const QString &str)
{
QJsonParseError err_rpt;
QJsonDocument root_Doc = QJsonDocument::fromJson(str.toUtf8(), &err_rpt);//字符串格式化为JSON
if (err_rpt.error != QJsonParseError::NoError)
{
QMessageBox::critical(this, QString::fromLocal8Bit("检查失败"), QString::fromLocal8Bit("服务器地址错误或JSON格式错误!"));
return -1;
}
if (root_Doc.isObject())
{
QJsonObject root_Obj = root_Doc.object(); //创建JSON对象,不是字符串
m_lastVerison = root_Obj.value("LatestVerison").toString(); //V1.0
m_strUrl = root_Obj.value("Url").toString();
QString UpdateTime = root_Obj.value("UpdateTime").toString();
QString ReleaseNote = root_Obj.value("ReleaseNote").toString();
if (m_lastVerison > m_CurVerison)
{
this->show();
QString warningStr = QString::fromLocal8Bit("检测到新版本!\n版本号:") + m_lastVerison + "\n" + QString::fromLocal8Bit("更新时间:") + UpdateTime + "\n" + QString::fromLocal8Bit("更新说明:") + ReleaseNote;
ui.textBrowser->append(warningStr);
}
else
{
QString strCurrentDir = QString(QString::fromLocal8Bit(Configer::GetInstance()->FilePath().c_str()));//当前程序运行路径
ExitApp(strCurrentDir + QString::fromStdString(Configer::GetInstance()->GetLocation()) + Configer::GetInstance()->GetRunExe().c_str());
}
}
return 0;
}
void AutoUpdate::replyFinished(QNetworkReply *reply)
{
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if (statusCode != 200)
{
//QMessageBox::critical(this, QString::fromLocal8Bit("Json文件下载失败 状态码:%1").arg(statusCode.toString()), reply->errorString());
return;
}
ParseJson(reply->readAll());
reply->deleteLater();
}
void AutoUpdate::slotUpdateNow()
{
//杀掉正在运行的进程
QProcess taskkill;
taskkill.execute("taskkill", QStringList() << "-im" << Configer::GetInstance()->GetRunExe().c_str() << "-f");
ui.stackedWidget->setCurrentWidget(ui.pageInfo);
ui.butNow->hide();
DownLoadXML();
}
void AutoUpdate::slotClose()
{
reject();
qApp->exit(0);
m_httpXML->DestroyData();
/*
this->close();*/
}
void AutoUpdate::onDownloadProgress(QString fileName,qint64 bytesReceived, qint64 bytesTotal)
{
ui.lblFileInfo->setText(fileName);
// 总时间
int nTime = m_downloadTime.elapsed();
// 本次下载所用时间
nTime -= m_nTime;
// 下载速度
double dBytesSpeed = (bytesReceived * 1000.0) / nTime;
double dSpeed = dBytesSpeed;
//剩余时间
qint64 leftBytes = (bytesTotal - bytesReceived);
double dLeftTime = (leftBytes * 1.0) / dBytesSpeed;
ui.lblSpeedInfo->setText(speed(dSpeed));
ui.lblLeftTime->setText(timeFormat(dLeftTime));
ui.lblFileInfoSize->setText(formatSize(bytesTotal));
ui.lblDownLoadInfo->setText(formatSize(bytesReceived));
ui.progressBar->setMaximum(bytesTotal);
ui.progressBar->setValue(bytesReceived);
// 获取上一次的时间
m_nTime = nTime;
}
void AutoUpdate::DownLoadXML()
{
/**从网页下载XML版本控制文件,里面记录了最新的文件版本**/
string str = Configer::GetInstance()->FilePath();
QString strDownLoad = QString::fromLocal8Bit(Configer::GetInstance()->FilePath().c_str()) + QString::fromStdString(Configer::GetInstance()->GetLocation());//存放下载文件的路径
QDir directory(strDownLoad);//如果路径不存在,则创建
if (!directory.exists())
{
directory.mkpath(strDownLoad);
}
QUrl url(QString::fromStdString(Configer::GetInstance()->GetXmlQurl()));
QFileInfo fileInfo(url.path());
m_strXmlName = fileInfo.fileName();
m_httpXML = new CHttpDownLoadFile(QString::fromStdString(Configer::GetInstance()->GetXmlQurl()), "", strDownLoad, this);//调用下载文件的类
connect(m_httpXML, SIGNAL(DownloadFinishedSignal()), this, SLOT(ReplyHttpFinished()));//发生错误时一样会发送此信号
m_httpXML->DownLoadFile();
}
QString AutoUpdate::GetElementVersion(const QString &xml, const QString &name)
{
QString result = "";
if (xml.isEmpty() || name.isEmpty())
{
qDebug() << "名称或者xml文件路径为空";
return result;
}
if (!QFile::exists(xml))
{
qDebug() << "xml文件不存在";
return result;
}
QFile file(xml);
if (file.open(QIODevice::ReadOnly | QFile::Text))//文件打开成功
{
QDomDocument doc;
QString errorStr;
int errorLine;
int errorColumn;
if (doc.setContent(&file, false, &errorStr, &errorLine, &errorColumn))
{
QDomElement root = doc.documentElement();
if (root.tagName() == "filelist")
{
int i = 0;
QDomNodeList nodeList = root.elementsByTagName("file");
for (; i<nodeList.size(); i++)
{
QString tempName = nodeList.at(i).toElement().attribute("name");
//QStringdir =nodeList.at(i).toElement().attribute("dir");
QString version = nodeList.at(i).toElement().attribute("version");
if (name == tempName)
{
qDebug() << "find!" << name;
result = version;
break;
}
}
if (i == nodeList.size())
{
qDebug() << "can'tfind!" << name;
}
}
else
{
qDebug() << "root.tagname!=filelist..";
}
}
else
{
qDebug() << "setcontenterror...";
}
file.close();
}
else
{
qDebug() << "openforreaderror...";
}
return result;
}
bool AutoUpdate::CheckVersion(const QString &v1, const QString &v2)
{
return v1 == v2;
}
int AutoUpdate::CheckUpdateFiles(const QString &xml1, const QString &xml2)
{
m_listFileDir.clear();
m_listFileName.clear();
if (xml1.isEmpty() || xml2.isEmpty())
return 0;
if (QFile::exists(xml2))
{
if (QFile::exists(xml1))
{
m_strTip = QString::fromLocal8Bit("检查需要更新的文件...");
QFile file(xml1);
if (file.open(QIODevice::ReadOnly | QFile::Text))//文件打开成功
{
QString errorStr;
int errorLine;
int errorColumn;
QDomDocument doc;
if (doc.setContent(&file, false, &errorStr, &errorLine, &errorColumn))
{
QDomElement root = doc.documentElement();
if (root.tagName() == "filelist")
{
QDomNodeList nodeList = root.elementsByTagName("file");
for (int i = 0; i<nodeList.size(); i++)
{
QString name = nodeList.at(i).toElement().attribute("name");
QString dir = nodeList.at(i).toElement().attribute("dir");
QString version = nodeList.at(i).toElement().attribute("version");
QString versionDownload = GetElementVersion(xml2, name);//获取本地xml文件对应文件(name)的版本信息
if (versionDownload.isEmpty())//本地XML没有此文件:下载,并放到相应的目录中
{
m_listFileDir.append(dir);
m_listFileName.append(name);
}
else
{
/**检查版本,如果本地版本低于下载的版本,则下载**/
if (!CheckVersion(version, versionDownload))
{
m_listFileDir.append(dir);
m_listFileName.append(name);
}
else
{
qDebug() << name << QString::fromLocal8Bit("文件是最新版本,不需要更新");
}
}
}
return 1;//此时要退出,避免关闭程序
}
else
{
m_strTip = "XML内容错误!";
return 0;
}
}
else
{
qDebug() << "setcontenterror...";
return 0;
}
file.close();
}
else
{
m_strTip = "不能打开更新文件!";
return 0;
}
}
else
{
m_strTip = "下载更新文件错误!";
return 0;
}
}
else
{
m_strTip = "本地的更新文件不存在!";
return 0;
}
}
void AutoUpdate::DownLoadUpdateFiles()
{
QString strServer = QString::fromStdString(Configer::GetInstance()->GetSerQurl());//需要下载的文件存储位置
QString strCurrentDir = QString(QString::fromLocal8Bit(Configer::GetInstance()->FilePath().c_str()));//当前程序运行路径
if (m_listFileDir.isEmpty() || m_listFileDir.isEmpty())
{
ExitApp(strCurrentDir + QString::fromLocal8Bit(Configer::GetInstance()->GetLocation().c_str()) + Configer::GetInstance()->GetRunExe().c_str());
return;
}
m_strTip = QString::fromLocal8Bit("开始下载更新文件...");
for (int i = 0; i<m_listFileName.size(); i++)
{
m_strTip = QString::fromLocal8Bit("正在下载文件") + m_listFileName.at(i);
ui.progressBar->setValue(100 * i / m_listFileName.size());
/**放置下载的文件的路径**/
QString temp = m_listFileDir.at(i);
QString tempdir = m_listFileDir.at(i);
if (!m_listFileDir.at(i).isEmpty())
{
temp = temp + "/";
tempdir = tempdir + "\\";
}
QString strPlaceDir = strCurrentDir + QString::fromStdString(Configer::GetInstance()->GetLocation()) + tempdir;
QDir directory(strPlaceDir);//如果路径不存在,则创建
if (!directory.exists())
directory.mkpath(strPlaceDir);
QString strFileDirServer = strServer + temp + m_listFileName.at(i);//文件在服务器中的存储位置
CHttpDownLoadFile *http = new CHttpDownLoadFile(strFileDirServer, "", strPlaceDir, this);//调用下载文件的类
http->DownLoadFile();
connect(http, SIGNAL(DownloadProcess(QString, qint64, qint64)), this, SLOT(onDownloadProgress(QString, qint64, qint64)));
m_downloadTime.start();
while (!http->m_bIsFinished)
{
if (http->m_nTotal == -1)
{
ui.progressBar->setValue(1);
}
else
{
ui.progressBar->setValue(100 * http->m_nReceived / http->m_nTotal);
}
QCoreApplication::processEvents();
}
m_strTip = QString::fromLocal8Bit("文件") + m_listFileName.at(i) + QString::fromLocal8Bit("下载完成");
///**将下载好的文件复制到主目录中,先删除原先的文件**/
//QString strLocalFileName = strCurrentDir + "\\" + m_listFileDir.at(i) + "\\" + m_listFileName.at(i);
//if (QFile::exists(strLocalFileName))QFile::remove(strLocalFileName);
//QDir directory1(strCurrentDir + "\\" + m_listFileDir.at(i));//如果路径不存在,则创建
//if (!directory1.exists())directory1.mkpath(strCurrentDir + "\\" + m_listFileDir.at(i));
//QFile::copy(strPlaceDir + "\\" + m_listFileName.at(i), strLocalFileName);
}
m_strTip = QString::fromLocal8Bit("更新完成!");
/**替换旧的xml文件**/
QString strNewXML = strCurrentDir + QString::fromStdString(Configer::GetInstance()->GetLocation()) + m_strXmlName;//最新的XML文件
QString strOldXML = strCurrentDir + "\\" + m_strXmlName;//旧的XML文件
QFile::remove(strOldXML);
QFile::copy(strNewXML, strOldXML);
ExitApp(strCurrentDir + QString::fromStdString(Configer::GetInstance()->GetLocation()) + Configer::GetInstance()->GetRunExe().c_str());
}
void AutoUpdate::ExitApp(const QString &name)
{
if (!name.isEmpty())
{
/**运行主程序,并且退出当前更新程序(说明:主程序在上上一级目录中)**/
//更新配置文件版本号
Configer::GetInstance()->SaveVersion(m_lastVerison.toStdString().c_str());
if (!QProcess::startDetached(name, QStringList()))//启动主程序,主程序在其上一级目录
{
QMessageBox::warning(this, QString::fromLocal8Bit("警告信息"), QString::fromLocal8Bit("启动主程序错误!\n可能主程序不存在或者被破坏!\n解决办法:重新安装程序!"));
}
}
this->close();
}
void AutoUpdate::ReplyHttpFinished()
{
CheckUpdateFiles(QString::fromLocal8Bit(Configer::GetInstance()->FilePath().c_str()) + QString::fromStdString(Configer::GetInstance()->GetLocation()) + m_strXmlName, QString::fromLocal8Bit(Configer::GetInstance()->FilePath().c_str()) + "\\" + m_strXmlName);
DownLoadUpdateFiles();
}
参考文章:https://blog.csdn.net/hulinhulin/article/details/46839107
由于博主只写了部分,所以自己实现了部分。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章