2.2.3 下载XML文件的DownLoadXML函数...8
2.2.6 比较两个XML文件CheckUpdateFiles.11
2.2.7 下载文件DownLoadUpdateFiles.13
软件下载地址:
软件自动更新解决方案及QT实现.rar-互联网文档类资源-CSDN下载
需要考虑解决的问题:
1) 需要知道哪些文件需要更新,哪些不需要;
2) 从哪里下载更新文件;
3) 将旧的文件用新的文件替换掉(包含版本控制文件);
4) 更新完毕后重新启动主程序;
第一个问题,可以为程序所使用的文件都设定一个版本号,版本号都记录在一个 XML 文件中,升级时,检查最新程序的版本控制文件和当前的版本控制文件,最新版本号较大时,表示该文件需要更新。如果一个文件不再需要了,则将该文件的版本信息从最新的版本控制文件中删除,通过对比控制文件,就知道该文件不再需要了,可以将之删除;
第二个问题,最新的版本控制文件需要放在一个可供方便下载的地方,例如FTP或者一个固定的IP;
第三个问题,通过对比新的版本控制文件和旧的版本控制文件来确定哪些需要替换或者删除;
第四个问题,更新程序运行完后,启动主程序即可,需要一个标识来说明是否更新完成;
按照以上的思路,下面对每一个步骤结合程序进行详细地阐述,软件使用QT5.1实现。
1 文件的版本控制-XML
下面是使用XML文件来表示的版本控制文件:
<?xml version="1.0"encoding="utf-8"?>
<filelist>
<filename="qico.dll" dir="imageformats"version="1.0"/>
<filename="qminimal.dll" dir="imageformats"version="1.0"/>
…..
<file name="main.exe"version="1.0"/>
</filelist>
Name表示文件的名称;
dir表示所在的目录(相对目录);
version表示当前文件的版本;
2 更新程序的实现
更新程序使用QT5.1来实现,最终生成一个可执行文件(exe文件)。新建工程时选择QT GUI应用,其他都默认,工程名为Updater。
2.1 界面设置
在构造函数中设置界面。
应用程序在屏幕中间:
QDesktopWidget *deskdop = QApplication::desktop();
this->move((deskdop->width() -this->width())/2, (deskdop->height() - this->height())/2);
无标题栏:
this->setWindowFlags(Qt::FramelessWindowHint);//没有标题栏
隐藏菜单栏和工具栏
this->ui->menuBar->hide();
this->ui->mainToolBar->hide();
固定高和宽:
this->setFixedSize(400,200);
设置背景颜色(两种方法都可以)
//this->setStyleSheet("QMainWindow{background:rgb(240,250,250)}");
QPalette pal;
pal.setColor(QPalette::Background,QColor(255,245,225) );
this->setPalette(pal);
this->setAutoFillBackground(true);
2.2 程序功能
程序功能包括从网络下载数据,分析XML文件,比较当前的XML及下载的XML文件,并最终确定哪些文件需要更新或者添加
2.2.1 下载网络数据
新建类CHttpDownLoadFile,类功能:从指定网络中下载指定的文件,并且存储到指定的本地文件目录中。
主要的成员函数及槽函数:
public slots:
void ReplyNewDataArrived();//响应m_netReply有新的数据到达
void ReplyFinished();//响应数据接收完成
public:
QNetworkAccessManager *m_netAccessManager;//网络参数
QNetworkReply *m_netReply;
QUrl m_urlAdress;//网络地址
QString m_strFileName;//需要下载的文件名
QString m_strDir;//文件的存储位置
QFile *m_file;//下载的文件
qint64m_nReceived;//下载文件时,已经接收的文件大小和总共大小
qint64m_nTotal;
主要函数及功能:
a.构造函数
CHttpDownloadFile(QString url,QStringfileName,QString dir,QObject *parent = 0);
url表示文件的网络地址;
filename表示文件名;
dir表示文件存储路径
如果fileName不为空,那么文件名使用fileName,否则从url提取(注:不需要加后缀)。如果dir不为空,那么将文件存储到dir指向的文件夹中,否则存储在默认路径中(即与可执行文件在同一个文件夹中),如果文件夹不存在,那么会创建,dir举例:c:/temp/,或者c:/temp,如果前面不加盘符,那么将会在默认文件夹中创建。
b. 开始下载文件的函数:void DownLoadFile()
m_netReply=m_netAccessManager->get(QNetworkRequest(m_urlAdress));
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))
{
qDebug()<<"不能存储文件:"<<m_strFileName;
delete m_file;
m_file = NULL;
return;
}
c.槽函数void ReplyFinished(),当下载网络数据结束时响应此函数,主要是释放资源
m_netAccessManager->deleteLater();
m_netReply->deleteLater();
m_file->close();
m_file->deleteLater();
d.槽函数voidReplyNewDataArrived()—当数据到达时调用此函数,并存储到指定的文件中
if(m_file)
{
m_file->write(m_netReply->readAll());
m_file->flush();//注意需要刷新
}
else
{
qDebug()<<m_netReply->readAll();
}
2.2.2 XML文件的分析
QFile file(filename);
if(!file.open(QIODevice::ReadOnly | QFile::Text)) {
qDebug()<<"open for read error..." ;
}
QString errorStr;
int errorLine;
int errorColumn;
QDomDocument doc;
if(!doc.setContent(&file, false, &errorStr, &errorLine,&errorColumn)) {
qDebug()<<"setcontent error..." ;
file.close();
}
file.close();
QDomElement root =doc.documentElement();
if (root.tagName() !="filelist")
{
qDebug()<<"root.tagname != filelist.." ;
}
else
{
QDomNodeListnodeList = root.elementsByTagName("file");
for(inti=0;i<nodeList.size();i++)
{
qDebug()<<nodeList.at(i).toElement().attribute("name")