建设企业网站的好处是什么,邢台做网站推广,如何做微信商城网站建设,产品网络推广的方法from#xff1a;https://blog.csdn.net/hulinhulin/article/details/46839107软件自动更新解决放案及QT实现...11 文件的版本控制-XML.22 更新程序的实现...22.1 界面设置...22.2 程序功能...32.2.1 下载网络数据...32.2.2 XML文件的分析...62.2.3 下载XML文件的DownLoadXML函…fromhttps://blog.csdn.net/hulinhulin/article/details/46839107软件自动更新解决放案及QT实现...11 文件的版本控制-XML.22 更新程序的实现...22.1 界面设置...22.2 程序功能...32.2.1 下载网络数据...32.2.2 XML文件的分析...62.2.3 下载XML文件的DownLoadXML函数...82.2.4 返回指定XML文件中的name版本号...82.2.5 返回指定XML文件中的name版本号...102.2.6 比较两个XML文件CheckUpdateFiles.112.2.7 下载文件DownLoadUpdateFiles.132.2.7 退出当前程序并启动指定的程序...163 更新程序的启动...163.1 从主程序启动更新程序...163.2 主程序的关闭...173.3 更新程序关闭时启动主程序...174 程序调试...17软件自动更新解决放案及QT实现需要考虑解决的问题1) 需要知道哪些文件需要更新哪些不需要2) 从哪里下载更新文件3) 将旧的文件用新的文件替换掉包含版本控制文件4) 更新完毕后重新启动主程序 第一个问题可以为程序所使用的文件都设定一个版本号版本号都记录在一个 XML 文件中升级时检查最新程序的版本控制文件和当前的版本控制文件最新版本号较大时表示该文件需要更新。如果一个文件不再需要了则将该文件的版本信息从最新的版本控制文件中删除通过对比控制文件就知道该文件不再需要了可以将之删除第二个问题最新的版本控制文件需要放在一个可供方便下载的地方例如FTP或者一个固定的IP第三个问题通过对比新的版本控制文件和旧的版本控制文件来确定哪些需要替换或者删除第四个问题更新程序运行完后启动主程序即可需要一个标识来说明是否更新完成 按照以上的思路下面对每一个步骤结合程序进行详细地阐述软件使用QT5.1实现。 1 文件的版本控制-XML下面是使用XML文件来表示的版本控制文件?xml version1.0encodingutf-8? filelist filenameqico.dll dirimageformatsversion1.0/ filenameqminimal.dll dirimageformatsversion1.0/….. file namemain.exeversion1.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_netReplym_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(inti0;inodeList.size();i) { qDebug()nodeList.at(i).toElement().attribute(name) nodeList.at(i).toElement().attribute(dir) nodeList.at(i).toElement().attribute(version); }} }这里只是将XML文件的内容输出详细的代码在工程Updater的其他函数中。2.2.3 下载XML文件的DownLoadXML函数函数下载XML文件当XML文件下载完成时发送下载完成信号提示进行下一步操作。 /**从网页下载XML版本控制文件里面记录了最新的文件版本**/ QStringstrCurrentDirQDir::currentPath();//当前程序运行路径 QStringstrDownLoadstrCurrentDir/download/;//存放下载文件的路径 QDirdirectory(strDownLoad);//如果路径不存在则创建 if(!directory.exists()) { directory.mkpath(strDownLoad); } m_httpXMLnewCHttpDownloadFile(http://www.***.com/download/**.xml,,strDownLoad,this);//调用下载文件的类 connect(m_httpXML,SIGNAL(DownloadFinishedSignal()),this,SLOT(ReplyHttpFinished()));//发生错误时一样会发送此信号m_httpXML-DownLoadFile();在ReplyHttpFinished()函数中需要错误处理。实例化m_httpXML时需要将parent设置为this这样当程序结束时会自动释放。2.2.4 返回指定XML文件中的name版本号 /***********在xml中查找名字与name相同的元素并返回版本号** *xml:xml文件的路径 *name:需要查找的元素名称 * *return:QString:版本号如果有则返回没有则为空 ************************************************/ QStringGetElementVersion(QStringxml,QStringname); 实现GetElementVersion(QStringxml,QStringname){ QStringresult; if(xml.isEmpty()||name.isEmpty()) { qDebug()名称或者xml文件路径为空; returnresult; } if(!QFile::exists(xml)) { qDebug()xml文件不存在; returnresult; } QFilefile(xml); if(file.open(QIODevice::ReadOnly|QFile::Text))//文件打开成功 { QDomDocumentdoc; if(doc.setContent(file)) { QDomElementrootdoc.documentElement(); if(root.tagName()filelist) { inti0; QDomNodeListnodeListroot.elementsByTagName(file); for(;inodeList.size();i) { QStringtempName nodeList.at(i).toElement().attribute(name); //QStringdir nodeList.at(i).toElement().attribute(dir); QStringversionnodeList.at(i).toElement().attribute(version); if(nametempName) { qDebug()find!name; resultversion; break; } } if(inodeList.size()) { qDebug()cantfind!name; } } else { qDebug()root.tagname!filelist..; } } else { qDebug()setcontenterror...; } file.close(); } else { qDebug()openforreaderror...; } returnresult;}2.2.5 返回指定XML文件中的name版本号 /**************比较两个版本号******************* *params: * v1,v2:两个版本号格式1.1.0,不能为空 * *return: * true:如果两个版本号码相同 * false:两个版本号不同 * *说明暂时只比较了是否相同 *******************************************/ boolCheckVersion(QStringv1,QStringv2);实现比较简单就不贴代码了。2.2.6 比较两个XML文件CheckUpdateFiles通过比较两个XML文件来确定需要下载的文件。/************比较两个XML文件**************** *params: * name1,name2:两个XML文件不能为空并且文件需要存在,name1必须是最新的xml文件刚刚下载下来的,name2是本地的xml文件; * *return: *0-someerrorhappens,elsesuccess *将需要更新的文件名存储到m_listFileName中 *路径存储到m_listFileDir中 * *注意m_listFileDir和m_listFileName的个数是一样的 * 如果没有元素表示所有的文件都不用更新 ******************************************/ intCheckUpdateFiles(QStringname1,QStringname2); 实现CheckUpdateFiles(QStringname1,QStringname2){ m_listFileDir.clear(); m_listFileName.clear(); if(name1.isEmpty()||name2.isEmpty())return0; if(QFile::exists(name2)) { if(QFile::exists(name1)) { m_strTip检查需要更新的文件...; QFilefile(name1); if(file.open(QIODevice::ReadOnly|QFile::Text))//文件打开成功 { QStringerrorStr; interrorLine; interrorColumn; QDomDocumentdoc; if(doc.setContent(file,false,errorStr,errorLine,errorColumn)) { QDomElementrootdoc.documentElement(); if(root.tagName()filelist) { QDomNodeListnodeListroot.elementsByTagName(file); for(inti0;inodeList.size();i) { QStringname nodeList.at(i).toElement().attribute(name); QStringdir nodeList.at(i).toElement().attribute(dir); QStringversionnodeList.at(i).toElement().attribute(version); QStringversionDownloadGetElementVersion(name2,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文件是最新版本不需要更新; } } } return1;//此时要退出避免关闭程序 } else { m_strTipXML内容错误; return0; } } else { qDebug()setcontenterror...; return0; } file.close(); } else { m_strTip不能打开更新文件; return0; } } else { m_strTip下载更新文件错误; return0; } } else { m_strTip本地的更新文件不存在; return0; }}2.2.7 下载文件DownLoadUpdateFiles 下载需要的文件完成后启动主程序 。/********下载最新的版本的文件并替换或者增加********************* *旧XML中有的文件新XML没有的此文件不做处理。 *下载信息由m_listFileName和m_listFileDir提供 *****************************************************/ voidDownLoadUpdateFiles();实现DownLoadUpdateFiles(){ QStringstrServerhttp://www.***.com/download/;//需要下载的文件存储位置 QStringstrCurrentDirQDir::currentPath();//当前程序运行路径 if(m_listFileDir.isEmpty()||m_listFileDir.isEmpty()) { qDebug()没有需要下载的文件1; ExitApp(strCurrentDir/main.exe); return; } m_strTip开始下载更新文件...; m_bIsFinishedfalse; for(inti0;im_listFileName.size();i) { m_strTip正在下载文件m_listFileName.at(i); m_progUpdate-setValue(100*i/m_listFileName.size()); /**放置下载的文件的路径**/ QStringstrPlaceDirstrCurrentDir/download/m_listFileDir.at(i); QDirdirectory(strPlaceDir);//如果路径不存在则创建 if(!directory.exists())directory.mkpath(strPlaceDir); QStringstrFileDirServerstrServerm_listFileDir.at(i)/m_listFileName.at(i);//文件在服务器中的存储位置 CHttpDownloadFile*httpnewCHttpDownloadFile(strFileDirServer,,strPlaceDir,this);//调用下载文件的类 http-DownLoadFile(); while(!http-m_bIsFinished) { if(http-m_nTotal-1) { m_progDownload-setValue(1); } else { m_progDownload-setValue(100*http-m_nReceived/http-m_nTotal); } QCoreApplication::processEvents(); } m_strTip文件m_listFileName.at(i)下载完成; /**将下载好的文件复制到主目录中先删除原先的文件**/ QStringstrLocalFileNamestrCurrentDir/m_listFileDir.at(i)/m_listFileName.at(i); if(QFile::exists(strLocalFileName))QFile::remove(strLocalFileName); QDirdirectory1(strCurrentDir/m_listFileDir.at(i));//如果路径不存在则创建 if(!directory1.exists())directory1.mkpath(strCurrentDir/m_listFileDir.at(i)); QFile::copy(strPlaceDir/m_listFileName.at(i),strLocalFileName); } m_bIsFinishedtrue; m_strTip更新完成; /**替换旧的xml文件**/ QStringstrNewXMLstrCurrentDir/download/**.xml;//最新的XML文件 QStringstrOldXMLstrCurrentDir/**.xml;//旧的XML文件 QFile::remove(strOldXML); QFile::copy(strNewXML,strOldXML); ExitApp(strCurrentDir/main.exe);}2.2.7 退出当前程序并启动指定的程序 /********退出当前程序并且启动需要的程序************************* *name:需要启动的程序可以使用相对位置 *程序不能使用exit(0),会发生线程错误这里使用this-close()函数 *****************************************************/实现ExitApp(QStringname){ if(!name.isEmpty()) { /**运行主程序并且退出当前更新程序(说明主程序在上上一级目录中)**/ if(!QProcess::startDetached(name))//启动主程序主程序在其上一级目录 { QMessageBox::warning(this,警告信息,启动主程序错误!\n可能主程序不存在或者被破坏!\n解决办法重新安装程序!); } } this-close();}3 更新程序的启动 更新程序是独立的可执行文件所以在启动主程序时首先启动更新程序注网络检查放在了更新程序中然后关闭主程序更新完成后再重新启动主程序。3.1 从主程序启动更新程序 首先需要判断是否需要启动更新程序避免更新后再次启动更新程序 将是否需要启动更新程序的参数放在软件的初始参数文件中例如params.txt文件中初始值为true表示需要启动更新程序。主程序启动时先获取里面的参数并判断是否需要启动更新程序。完成更新后将此参数设置为false表示下次再次启动主程序时不需更新当点击关闭主程序时再次将此参数设置为true这样就可以保证每次启动时都会检查更新启动更新程序调用QProcess::startDetached()方法启动外部程序后立即返回也就是主程序也运行即使主程序关闭启动的程序也会运行本程序使用这个方法因为更新后。注如果调用QProcess::execute函数此方法可以阻塞主程序的运行直到启动的程序关闭因为需要关闭主程序还要重新启动更新后得程序所以不能使用这个方法。3.2 主程序的关闭 如果QProcess::startDetached方法返回true则关闭主程序调用exit(0)或者quit()方法3.3 更新程序关闭时启动主程序更新程序结束时调用QProcess::startDetached(main.exe)主程序和更新程序在同一目录。但是在关闭更新程序的时候使用exit会发送错误错误原因会出现夸线程发送信号的情况这是不容许的。当所有文件都下载完成时使用close函数。4 程序调试需要调试以下功能(1)主程序启动时检测是否需要启动更新程序, 检测params.cq文件里面的is_update参数的值如果为1则启动否则不启动代码在CLoginBox的构造函数中(2)如果is_update1那么启动更新程序更新程序启动后is_update设置为0(3)主程序退出时将is_update设置为1,即每次重新启动主程序的时候都需要检查更新(4)正确下载xml文件存储位置与主程序同目录下的download文件 夹中特别提醒由于更新程序是从主程序中调用的所以在更新程序中调用获取当前运行程序的目录是得到的是主程序的的目录但是如果更新程序单独运行的话得到的目录是和更新程序目录一样的所以最好的方式就是讲主程序和更新程序放在同一个目录中(5)是否正确调用了更新程序里面的CheckUpdateFiles函数主要是检查是否输入正确的xml文件目录(6)下载的更新文件是否正确放置(7)下载完后旧的XML是否换成新的XML(8)运行主程序的电脑或者服务端没有网络的情况版权声明本文为博主原创文章未经博主允许不得转载。 https://blog.csdn.net/hulinhulin/article/details/46839107