用C#实现软件自动更新思路
长期以来,广大程序员为到底是使用Client/Server,还是使用Browser/Server结构争论不休,在这些争论当中,C/S结构的程序可维护性差,布置困难,升级不方便,维护成本高就是一个相当重要的因素。有很多企业用户就是因为这个原因而放弃使用C/S。然而当一个应用必须要使用C /S结构才能很好的实现其功能的时候,我们该如何解决客户端的部署与自动升级问题?部署很简单,只要点击安装程序即可,难的在于每当有新版本发布时,能够实现自动升级[3]。现在好了,我们的目标很简单,我们希望开发一个与具体应用无关的能够复用的自动升级系统。下面我为大家提供了一套可复用的用C#编写的自动升级系统。
2 实现软件的自动升级存在的困难
第一,为了查找远程服务器上的更新,应用程序必须有查询网络的途径,这需要网络编程、简单的应用程序与服务器通讯的协议。
第二是下载。下载看起来不需要考虑联网的问题,但要考虑下载用户请求的文件,以及在没有用户同意时下载大文件。友好的自动更新应用程序将使用剩余的带宽下载更新。这听起来简单,但却是一个技术难题,幸运的是已经有了解决方法。
第三个考虑因素是使用新版应用程序更换原应用程序的过程。这个问题比较有趣,因为它要求代码运行时将自己从系统删除,有多种办法可以实现该功能[5],本文程序主要通过比较新旧版本的日期号来实现替换新版本应用程序的功能。
3 实现软件自动在线升级的原理
写两个程序,一个是主程序;一个是升级程序;所有升级任务都由升级程序完成。
1.启动升级程序,升级程序连接到网站,下载新的主程序(当然还包括支持的库文件、XML配置文档等)到临时文件夹;
2.升级程序获取服务器端XML配置文件中新版本程序的更新日期或版本号或文件大小;
3.升级程序获取原有客户端应用程序的最近一次更新日期或版本号或文件大小,两者进行比较;如果发现升级程序的日期大于原有程序的最新日期,则提示用户是否升级;或者是采用将现有版本与最新版本作比较,发现最新的则提示用户是否升级;也有人用其它属性如文件大小进行比较,发现升级程序的文件大小大于旧版本的程序的大小则提示用户升级。本文主要采用比较新旧版本更新日期号来提示用户升级。
4.如果用户选择升级,则获取下载文件列表,开始进行批量下载文档;
5.升级程序检测旧的主程序是否活动,若活动则关闭旧的主程序;
6.删除旧的主程序,拷贝临时文件夹中的文件到相应的位置;
7.检查主程序的状态,若状态为活动的,则启动新的主程序;
8.关闭升级程序,升级完成[4]。
4 用C#实现在线升级的关键步骤
这里我主要使用日期信息来检测是否需要下载升级版本。
4.1 准备一个XML配置文件
名称为AutoUpdater.xml,作用是作为一个升级用的模板,显示需要升级的信息。
名称为AutoUpdater.xml,作用是作为一个升级用的模板,显示需要升级的信息。
01
|
<?xml version="1.0"?> //xml版本号
|
02
|
<AutoUpdater>
|
03
|
<URLAddres URL="http://192.168.198.113/vbroker/log/"/>//升级文件所在服务器端的网址
|
04
|
<UpdateInfo>
|
05
|
<UpdateTime Date = "2005-02-02"/> //升级文件的更新日期
|
06
|
<Version Num = "1.0.0.1"/> //升级文件的版本号
|
07
|
</UpdateInfo>
|
08
|
<UpdateFileList> //升级文件列表
|
09
|
<UpdateFile FileName = "aa.txt"/> //共有三个文件需升级
|
10
|
<UpdateFile FileName = "VB40.rar"/>
|
11
|
<UpdateFile FileName = "VB4-1.CAB"/>
|
12
|
</UpdateFileList>
|
13
|
<RestartApp>
|
14
|
<ReStart Allow = "Yes"/> //允许重新启动应用程序
|
15
|
<AppName Name = "TIMS.exe"/> //启动的应用程序名
|
16
|
</RestartApp>
|
17
|
</AutoUpdater>
|
18
|
19
|
//xml版本号
|
20
|
//升级文件所在服务器端的网址
|
21
|
//升级文件的更新日期
|
22
|
//升级文件的版本号
|
23
|
//升级文件列表
|
24
|
//共有三个文件需升级
|
25
|
//允许重新启动应用程序
|
26
|
//启动的应用程序名
|
从以上XML文档中可以得知升级文档所在服务器端的地址、升级文档的更新日期、需要升级的文件列表,其中共有三个文件需升级:aa.txt、VB40.rar、VB4-1.CAB。以及是否允许重新启动应用程序和重新启动的应用程序名。
4.2 获取客户端应用程序及服务器端升级程序的最近一次更新日期
通过GetTheLastUpdateTime()函数来实现。
01
|
private string GetTheLastUpdateTime( string Dir)
|
02
|
{
|
03
|
string LastUpdateTime = "" ;
|
04
|
string AutoUpdaterFileName = Dir + @"\AutoUpdater.xml" ;
|
05
|
if (!File.Exists(AutoUpdaterFileName))
|
06
|
return LastUpdateTime;
|
07
|
//打开xml文件
|
08
|
FileStream myFile = new FileStream(AutoUpdaterFileName,FileMode.Open);
|
09
|
//xml文件阅读器
|
10
|
XmlTextReader xml = new XmlTextReader(myFile);
|
11
|
while (xml.Read())
|
12
|
{
|
13
|
if (xml.Name == "UpdateTime" )
|
14
|
{
|
15
|
//获取升级文档的最后一次更新日期
|
16
|
LastUpdateTime = xml.GetAttribute( "Date" );
|
17
|
break ;
|
18
|
}
|
19
|
}
|
20
|
xml.Close();
|
21
|
myFile.Close();
|
22
|
return LastUpdateTime;
|
23
|
}
|
通过XmlTextReader打开XML文档,读取更新时间从而获取Date对应的值,即服务器端升级文件的最近一次更新时间。
函数调用实现:
//获取客户端指定路径下的应用程序最近一次更新时间
string thePreUpdateDate = GetTheLastUpdateTime(Application.StartupPath);
Application.StartupPath指客户端应用程序所在的路径。
//获得从服务器端已下载文档的最近一次更新日期
string theLastsUpdateDate = GetTheLastUpdateTime(theFolder.FullName);
theFolder.FullName指在升级文档下载到客户机上的临时文件夹所在的路径。
4.3 比较日期
客户端应用程序最近一次更新日期与服务器端升级程序的最近一次更新日期进行比较。
01
|
//获得已下载文档的最近一次更新日期
|
02
|
string theLastsUpdateDate = GetTheLastUpdateTime(theFolder.FullName);
|
03
|
if (thePreUpdateDate != "" )
|
04
|
{
|
05
|
//如果客户端将升级的应用程序的更新日期大于服务器端升级的应用程序的更新日期
|
06
|
if (Convert.ToDateTime(thePreUpdateDate)>=Convert.ToDateTime(theLastsUpdateDate))
|
07
|
{
|
08
|
MessageBox.Show( "当前软件已经是最新的,无需更新!" , "系统提示" ,MessageBoxButtons.OK,MessageBoxIcon.Information);
|
09
|
this .Close();
|
10
|
}
|
11
|
}
|
12
|
this .labDownFile.Text = "下载更新文件" ;
|
13
|
this .labFileName.Refresh();
|
14
|
this .btnCancel.Enabled = true ;
|
15
|
this .progressBar.Position = 0;
|
16
|
this .progressBarTotal.Position = 0;
|
17
|
this .progressBarTotal.Refresh();
|
18
|
this .progressBar.Refresh();
|
19
|
20
|
//通过动态数组获取下载文件的列表
|
21
|
ArrayList List = GetDownFileList(GetTheUpdateURL(),theFolder.FullName);
|
22
|
string [] urls = new string [List.Count];
|
23
|
List.CopyTo(urls, 0);
|
将客户端升级的应用程序的日期与服务器端下载的应用程序日期进行比较,如果前者大于后者,则不更新;如果前者小于后者,则通过动态数组获取下载文件的列表,开始下载文件。
4.2 获取客户端应用程序及服务器端升级程序的最近一次更新日期
通过GetTheLastUpdateTime()函数来实现。
01
|
private string GetTheLastUpdateTime( string Dir)
|
02
|
{
|
03
|
string LastUpdateTime = "" ;
|
04
|
string AutoUpdaterFileName = Dir + @"\AutoUpdater.xml" ;
|
05
|
if (!File.Exists(AutoUpdaterFileName))
|
06
|
return LastUpdateTime;
|
07
|
//打开xml文件
|
08
|
FileStream myFile = new FileStream(AutoUpdaterFileName,FileMode.Open);
|
09
|
//xml文件阅读器
|
10
|
XmlTextReader xml = new XmlTextReader(myFile);
|
11
|
while (xml.Read())
|
12
|
{
|
13
|
if (xml.Name == "UpdateTime" )
|
14
|
{
|
15
|
//获取升级文档的最后一次更新日期
|
16
|
LastUpdateTime = xml.GetAttribute( "Date" );
|
17
|
break ;
|
18
|
}
|
19
|
}
|
20
|
xml.Close();
|
21
|
myFile.Close();
|
22
|
return LastUpdateTime;
|
23
|
}
|
通过XmlTextReader打开XML文档,读取更新时间从而获取Date对应的值,即服务器端升级文件的最近一次更新时间。
函数调用实现:
//获取客户端指定路径下的应用程序最近一次更新时间
string thePreUpdateDate = GetTheLastUpdateTime(Application.StartupPath);
Application.StartupPath指客户端应用程序所在的路径。
//获得从服务器端已下载文档的最近一次更新日期
string theLastsUpdateDate = GetTheLastUpdateTime(theFolder.FullName);
theFolder.FullName指在升级文档下载到客户机上的临时文件夹所在的路径。
4.3 比较日期
客户端应用程序最近一次更新日期与服务器端升级程序的最近一次更新日期进行比较。
01
|
//获得已下载文档的最近一次更新日期
|
02
|
string theLastsUpdateDate = GetTheLastUpdateTime(theFolder.FullName);
|
03
|
if (thePreUpdateDate != "" )
|
04
|
{
|
05
|
//如果客户端将升级的应用程序的更新日期大于服务器端升级的应用程序的更新日期
|
06
|
if (Convert.ToDateTime(thePreUpdateDate)>=Convert.ToDateTime(theLastsUpdateDate))
|
07
|
{
|
08
|
MessageBox.Show( "当前软件已经是最新的,无需更新!" , "系统提示" ,MessageBoxButtons.OK,MessageBoxIcon.Information);
|
09
|
this .Close();
|
10
|
}
|
11
|
}
|
12
|
this .labDownFile.Text = "下载更新文件" ;
|
13
|
this .labFileName.Refresh();
|
14
|
this .btnCancel.Enabled = true ;
|
15
|
this .progressBar.Position = 0;
|
16
|
this .progressBarTotal.Position = 0;
|
17
|
this .progressBarTotal.Refresh();
|
18
|
this .progressBar.Refresh();
|
1
|
//通过动态数组获取下载文件的列表
|
2
|
ArrayList List = GetDownFileList(GetTheUpdateURL(),theFolder.FullName);
|
3
|
string [] urls = new string [List.Count];
|
4
|
List.CopyTo(urls, 0);
|
将客户端升级的应用程序的日期与服务器端下载的应用程序日期进行比较,如果前者大于后者,则不更新;如果前者小于后者,则通过动态数组获取下载文件的列表,开始下载文件。
通过BatchDownload()函数来实现。升级程序检测旧的主程序是否活动,若活动则关闭旧的主程序;删除旧的主程序,拷贝临时文件夹中的文件到相应的位置;检查主程序的状态,若状态为活动的,则启动新的主程序。
01
|
private void BatchDownload( object data)
|
02
|
{
|
03
|
this .Invoke( this .activeStateChanger, new object []{ true , false });
|
04
|
try
|
05
|
{
|
06
|
DownloadInstructions instructions = (DownloadInstructions) data;
|
07
|
//批量下载
|
08
|
using (BatchDownloader bDL = new BatchDownloader())
|
09
|
{
|
10
|
bDL.CurrentProgressChanged += new DownloadProgressHandler( this .SingleProgressChanged);
|
11
|
bDL.StateChanged += new DownloadProgressHandler( this .StateChanged);
|
12
|
bDL.FileChanged += new DownloadProgressHandler(bDL_FileChanged);
|
13
|
bDL.TotalProgressChanged += new DownloadProgressHandler(bDL_TotalProgressChanged);
|
14
|
bDL.Download(instructions.URLs, instructions.Destination, (ManualResetEvent) this .cancelEvent);
|
15
|
}
|
16
|
}
|
17
|
catch (Exception ex)
|
18
|
{
|
19
|
ShowErrorMessage(ex);
|
20
|
}
|
21
|
this .Invoke( this .activeStateChanger, new object []{ false , false });
|
22
|
this .labFileName.Text = "" ;
|
23
|
//更新程序
|
24
|
if ( this ._Update)
|
25
|
{
|
26
|
//关闭原有的应用程序
|
27
|
this .labDownFile.Text = "正在关闭程序...." ;
|
28
|
System.Diagnostics.Process[]proc=System.Diagnostics.Process.GetProcessesByName( "TIMS" );
|
29
|
//关闭原有应用程序的所有进程
|
30
|
foreach (System.Diagnostics.Process pro in proc)
|
31
|
{
|
32
|
pro.Kill();
|
33
|
}
|
34
|
DirectoryInfo theFolder= new DirectoryInfo(Path.GetTempPath()+"JurassicUpdate");
|
35
|
if (theFolder.Exists)
|
36
|
{
|
37
|
foreach (FileInfo theFile in theFolder.GetFiles())
|
38
|
{
|
39
|
//如果临时文件夹下存在与应用程序所在目录下的文件同名的文件,则删除应用程序目录下的文件
|
40
|
if (File.Exists(Application.StartupPath + \\"+Path.GetFileName(theFile.FullName)))
|
41
|
File.Delete(Application.StartupPath + "\\" +Path.GetFileName(theFile.FullName));
|
42
|
//将临时文件夹的文件移到应用程序所在的目录下
|
43
|
File.Move(theFile.FullName,Application.StartupPath + \\"+Path.GetFileName(theFile.FullName));
|
44
|
}
|
45
|
}
|
46
|
//启动安装程序
|
47
|
this .labDownFile.Text = "正在启动程序...." ;
|
48
|
System.Diagnostics.Process.Start(Application.StartupPath + "\\" + "TIMS.exe" );
|
49
|
this .Close();
|
50
|
}
|
51
|
}
|
转载于:https://www.cnblogs.com/gc2013/p/3668927.html
用C#实现软件自动更新思路相关推荐
- [转载]C#实现软件自动更新思路
转自:IT实验室 1 前言 长期以来,广大程序员为到底是使用Client/Server,还是使用Browser/Server结构争 论不休,在这些争论当中,C/S结构的程序可维护性差,布置困难,升级不 ...
- 软件自动更新解决方案及QT实现
from:https://blog.csdn.net/hulinhulin/article/details/46839107 软件自动更新解决放案及QT实现...1 1 文件的版本控制-XML.2 2 ...
- 软件自动更新功能的实现
今天一朋友在群里面问,软件自动更新功能怎么做,大家都不知道怎么搞,我下午刚好没事情,就研究了下. 附上我的源代码 考虑下基本的思路 1 .客户端(主程序)调用升级程序,升级程序连接到最新的服务器上. ...
- 软件自动更新解决方案及QT实现(源码已上传)
软件自动更新解决放案及QT实现...1 1 文件的版本控制-XML.2 2 更新程序的实现...2 2.1 界面设置...2 2.2 程序功能...3 2.2.1 下载网络数据...3 2.2.2 X ...
- C#软件自动更新程序
2019独角兽企业重金招聘Python工程师标准>>> 基于C#实现的软件自动更新程序,之前在网上搜集了两款软件自动更新程序,在实际应用中,对部分BUG进行修复,添加+完善一些功能. ...
- Android - 软件自动更新的实现
Android - 软件自动更新的实现 2012年11月18日 天气慢慢变凉了,给位亲,注意保暖啊. 接触到一个很实用的技术,那就是软件自动更新.一般开发者是通过自行在应用平台添加更新版本的apk.这 ...
- 《『若水新闻』客户端开发教程》——17.软件自动更新
本节课的主要内容: 1.增加软件自动更新功能 课程下载: http://115.com/file/e77ow25d
- 如何屏蔽 iOS 16 软件自动更新,去除更新通知和标记
如何禁用 iPhone.iPad 软件自动更新.适用于 iOS.iPadOS 和 watchOS,即 iPhone.iPad 和 Apple Watch 通用. 请访问原文链接:https://sys ...
- MAC 关闭office软件自动更新提示 (Microsoft AutoUpdate)
MAC 关闭office软件自动更新提示 (Microsoft AutoUpdate) cd /Library/Application\ Support/Microsoft/MAU2.0 sudo c ...
- 【Electron】酷家乐客户端开发实践分享 — 软件自动更新
作者:钟离,酷家乐PC客户端负责人 原文地址:webfe.kujiale.com/electron-au- 酷家乐客户端:下载地址 www.kujiale.com/activity/13- 文章背景: ...
最新文章
- 3.7 注意力模型直观理解-深度学习第五课《序列模型》-Stanford吴恩达教授
- mysql 数据迁移java_使用jdk进行数据迁移(sqlite迁移mysql)
- 主席树 - 可持久化线段树
- 记一次axios源码排查
- 遇到 java.io.EOFException 异常的解决办法
- 【Android studio快捷键】代码提示
- docker安装详细教程
- 【理论】RS-232、RS-485、RS-422通信接口标准介绍
- 小程序 自定义气泡框
- DotSoft.C3DTools.v7.0.0.3民用勘测地图和GIS工具集合
- office2010所做更改会影响共用模板normal
- LeetCode 1比特与比特字符
- html图片格式有什么,jpeg是一种什么格式?
- 使用OpenResty达到十万级并发超高性能Web应用(一):HelloWorld
- OpenCL ICD Loader运行测试暨解决报错:ERROR: App log and stub log differ.
- 单片机—外部中断与定时器 学习笔记
- 回望2018,这6家AI+教育公司亮了!| AI最佳掘金案例榜...
- 小米手环 android版本区别,小米手环光感版和标准版有什么区别 区别对别分析
- MySQL数据库 *实验报告6 查询where子句
- jlink 固件升级
热门文章
- C#WinForm开发在选项卡tab中集成加载多个窗体,通过选项卡切换窗体(超详细讲解)
- 解决SVN Files 的值“xxxxxxx .mine”无效 问题
- MySQL 开启慢查询日志
- SpringCloud实战(一)基于nacos实现订单+视频服务的调用
- JavaWeb——Servlet(入门必备,web请求与响应的底层)
- yum在linux安装mysql数据库_linux安装mysql(yum安装,比较简单)
- flash代码_Flash如何处理常见的代码错误(AS3)(2)
- ue4 命名插件_实时渲染模拟每根头发丝!新版UE4在实时毛发方面的实验性新功能...
- HighCharts:隐藏最下方logo
- 正则表达式:JS在一段HTML文字中找出所有img标签的src属性