Windows程序通用自动更新模块(C#,.NET4.5以上)
本通用自动更新模块适合所有Windows桌面程序的自动更新,不论语言,无论Winform还是wpf。
一、工作流程:
1. 主程序A调起升级程序B
2. B从服务器获取更新程序列表,打印更新信息。
3. B杀死A进程(此步骤可以放在步骤2~5任意位置)
4. B根据更新信息中指示的地址,下载更新程序包(.zip文件)
5. 解压缩.zip文件到一个新创建的文件夹
6. 将解压后的文件拷贝到原始文件目录,做替换。
7. 删除下载的.zip文件以及解压后创建的文件夹
8. B打开A
二、源码介绍:
升级程序B的实现:
更新信息列表用于存储版本信息,以及更新说明信息。通常为json或xml文件。本文为json文件。
存储列表信息的类
public class UpdateItem
{
public string Version { get; set; } //版本号
public string UpdateContent { get; set; } //更新信息
public string DownloadUri { get; set; } //更新包的下载地址
public string Time { get; set; } //更新时间
public string Size { get; set; } //更新包大小
}
获取更新信息使用WebClient.DownloadData(Uri),其中使用Newtonsoft.Json进行json序列化及反序列化。
WebClient client = new WebClient();
byte[] data = client.DownloadData(uri);
//json转为UpdateItem类对象
UpdateInfo = Newtonsoft.Json.JsonConvert.DeserializeObject<UpdateItem>(Encoding.UTF8.GetString(data));
获取更新信息以后在界面上进行输出。
下面介绍一下生成更新信息的json文件并使用FTP上传到服务器的代码。json文件也可以手动写,手动上传。不是重点,不想看可以跳到下一部分。
UpdateItem UpdateInfo = new UpdateItem();
... //赋值
string json = JsonConvert.SerializeObject(UpdateInfo);
//连接服务器
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://...");
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential("账号", "密码");
// 复制字符
byte[] fileContents = Encoding.UTF8.GetBytes(json);
request.ContentLength = fileContents.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(fileContents, 0, fileContents.Length);
requestStream.Close();
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
response.Close();
下载更新包zip文件
下载使用WebClient.DownloadFile(Uri, string)
string dir = System.IO.Directory.GetCurrentDirectory(); //程序所在文件夹路径
string zipfile = System.IO.Path.Combine(dir, "file.zip"); //下载后zip文件的完整路径 WebClient client = new WebClient();
client.DownloadFile(UpdateInfo.DownloadUri, zipfile);
return true;
解压缩zip文件
解压缩需要用到System.IO.Compression.ZipFile,需要.NET4.5及以上。如果用不了(找不到ZipFile),请检查是否已添加引用System.IO.Compression.FileSystem程序集。
代码只有一行,两个参数分别为zip文件完整路径,解压后的文件夹完整路径。
ZipFile.ExtractToDirectory(zipfile, extractPath);
使用第三方压缩软件生成的.zip文件有可能会解压失败,建议使用下方代码生成。两个参数分别为需要压缩的文件夹完整路径,生成的zip文件完整路径。
ZipFile.CreateFromDirectory(startPath, zipfile);
拷贝解压后的文件到原始目录
foreach (string item in Directory.GetFiles(extractPath))
{
File.Copy(item, System.IO.Path.Combine(dir, System.IO.Path.GetFileName(item)), true);
}
删除临时文件
File.Delete(zipfile);
DirectoryInfo di = new DirectoryInfo(extractPath);
di.Delete(true);
B进程杀死A进程
string appname = "file"; //A名字,不要路径,不要.exe
Process[] processes = Process.GetProcessesByName(appname);
foreach (var p in processes)
p.Kill();
B进程调起A进程
System.Diagnostics.Process.Start(@"path"); //完整路径
主要流程就是这些,建议用异步操作实现。
现在上号比较少,私信很多要代码的都没回…以后都会把完整代码附上的。
下面是完整代码。
private Uri uri = new Uri(@"http://..."); //更新信息列表文件路径
private UpdateItem UpdateInfo; //UpdateItem类的定义在前面第一部分说明 public MainWindow()
{
InitializeComponent();
LoadingData();
} //用户按下更新按钮
private async void Button_Click(object sender, RoutedEventArgs e)
{
//下载
Tb_State.Text = "正在下载新版本文件,请耐心等待";
string dir = System.IO.Directory.GetCurrentDirectory();
string zipfile = System.IO.Path.Combine(dir, "File.zip");
bool success = await Task.Run(() =>
{
try
{
WebClient client = new WebClient();
client.DownloadFile(UpdateInfo.DownloadUri, zipfile);
return true;
}
catch (Exception)
{
return false;
}
}); if (success)
Tb_State.Text = "文件已下载,正在复制文件";
else
{
Tb_State.Text = "下载新版本文件失败,请重试";
return;
} //杀死主程序进程
string appname = "File";
Process[] processes = Process.GetProcessesByName(appname);
foreach (var p in processes)
p.Kill(); //解压缩+拷贝+删除
bool success2 = await Task.Run(() =>
{
try
{
string extractPath = System.IO.Path.Combine(dir, "NewVersion");
ZipFile.ExtractToDirectory(zipfile, extractPath);
foreach (string item in Directory.GetFiles(extractPath))
File.Copy(item, System.IO.Path.Combine(dir, System.IO.Path.GetFileName(item)), true);
File.Delete(zipfile);
DirectoryInfo di = new DirectoryInfo(extractPath);
di.Delete(true);
return true;
}
catch (Exception)
{
return false;
}
}); if (success2)
Tb_State.Text = "更新完成,您可以点击下方按钮启动应用";
else
Tb_State.Text = "复制更新文件出错,请重试";
} //读取更新列表文件
private async Task<bool> LoadingData()
{
Tb_State.Text = "正在下载更新文件信息";
bool success = await Task.Run(() =>
{
try
{
WebClient client = new WebClient();
byte[] data = client.DownloadData(uri);
UpdateInfo = Newtonsoft.Json.JsonConvert.DeserializeObject<UpdateItem>(Encoding.UTF8.GetString(data));
return true;
}
catch (Exception)
{
return false;
}
}); if (success)
Tb_State.Text = "已获取新版本信息,可进行更新";
else
Tb_State.Text = "无法获取更新信息";
return success;
} //更新完成,更新程序B调起主程序A
private void Btn_Open_Click(object sender, RoutedEventArgs e)
{
System.Diagnostics.Process.Start(@"D:\..."); //A程序完整路径
}
再贴一个用于下载过程中,能实时显示已下载文件大小的代码
此部分需写在下载部分之前。
System.Windows.Threading.DispatcherTimer dt = new System.Windows.Threading.DispatcherTimer();
dt.Interval = TimeSpan.FromMilliseconds(100); //100毫秒
dt.Tick += (x, y) => {
if (File.Exists(zipfile) == false)
return;
string size = ((new FileInfo(zipfile).Length) / 1024.0 / 1024).ToString("f2");
if (download == false) //是否下载完毕
Tb_State.Text = size + "MB / " + UpdateInfo.Size; //输出:已下载/总大小
else
dt.Stop();
};
dt.Start();
代码部分执行时,再次执行代码可能会报错。可能原因包括下载zip文件后未删除再次下载报错等。如要做项目还有很多地方需要进行判断,如检测路径的合法性等。为了代码便于阅读,没有加入这些错误检测部分,需自行补充。几乎所有操作前都应判断路径合法性,以及目标位置的文件是否存在(是否需要先删除)等。只能说是在输入合法的情况下,完整执行此代码是没有问题的。
代码通过Visual Studio 2019测试,.NET4.5。
Windows程序通用自动更新模块(C#,.NET4.5以上)的更多相关文章
- Winform开发框架之通用自动更新模块(转)
在网络化的环境中,特别是基于互联网发布的Winform程序,程序的自动更新功能是比较重要的操作,这样可以避免挨个给使用者打电话.发信息通知或者发送软件等,要求其对应用程序进行升级.实现程序的自动更新, ...
- winform 通用自动更新程序
通用自动更新程序 主要功能: 1. 可用于 C/S 程序的更新,集成到宿主主程序非常简单和配置非常简单,或不集成到主程序独立运行. 2. 支持 HTTP.FTP.WebService等多种更新下载方式 ...
- WinForm通用自动更新器AutoUpdater项目实战
一.项目背景介绍 最近单位开发一个项目,其中需要用到自动升级功能.因为自动升级是一个比较常用的功能,可能会在很多程序中用到,于是,我就想写一个自动升级的组件,在应用程序中,只需要引用这个自动升级组件, ...
- 分析nuget源码,用nuget + nuget.server实现winform程序的自动更新
源起 (个人理解)包管理最开始应该是从java平台下的maven开始吧,因为java的开发大多数是基于开源组件开发的,一个开源包在使用时很可能要去依赖其他的开源包,而且必须是特定的版本才可以.以往在找 ...
- Android应用程序的自动更新升级(自身升级、通过tomcat)(转)
Android应用程序的自动更新升级(自身升级.通过tomcat) http://blog.csdn.net/mu0206mu/article/details/7204746 刚入手android一个 ...
- 【实用篇】Android之应用程序实现自动更新功能
我个人用的是友盟提供的自动更新组件,因此在这里只描述如何实用友盟提供的组件来完成程序的自动更新,步骤如下: 1.登录友盟官网,点击注册一个友盟账号. 2.注册成功后将会自动进入到添加新应用界面,选择添 ...
- 安卓程序代写 网上程序代写[原]Android应用的自动更新模块
软件的自动更新一般都与Splash界面绑定在一起, 由于需要维护的软件界面很复杂, 一个Activity中嵌入ViewPager, 并且逻辑比较复杂, 索性重新写一个Activity, 现在的软件都很 ...
- windows下svn自动更新
配置hooks下post-commit.bat文件,文件内容如下 @echo offSET REPOS=%1SET REV=%2SET DIR=%REPOS%/hooksSET PATH=%PATH% ...
- 【Android 应用开发】Android应用的自动更新模块
. 作者 :万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/18964835 . 软件的自动更新一般都与Splash界 ...
随机推荐
- 容器编排系统之ReplicaSet和Deployment控制器
前文我们了解了k8s上的Pod资源的生命周期.健康状态和就绪状态探测以及资源限制相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/14143610.htm ...
- 谁再问Servlet的问题,我就亲自上门来教学了
1. 概述 在这篇简短的文章中,我们将从概念上理解什么是servlet 和 servlet 容器以及它们是如何工作的. 同时,还能在请求.响应.会话对象.共享变量和多线程的上下文中看到它们的身影. 2 ...
- react第八单元(什么是纯函数-组件的性能优化-pureComponent-组件性能优化的原理)
课程目标 理解纯函数 熟练掌握组件性能优化的几种技巧 pureComponent和Component的区别 #知识点 一个函数的返回结果只依赖于它的参数,并且在执行过程里面没有副作用,我们就把这个函数 ...
- pytorch固定BN层参数
背景:基于PyTorch的模型,想固定主分支参数,只训练子分支,结果发现在不同epoch相同的测试数据经过主分支输出的结果不同. 原因:未固定主分支BN层中的running_mean和running_ ...
- Java生产环境下性能监控与调优详解视频教程 百度云 网盘
集数合计:9章Java视频教程详情描述:A0193<Java生产环境下性能监控与调优详解视频教程>软件开发只是第一步,上线后的性能监控与调优才是更为重要的一步本课程将为你讲解如何在生产环境 ...
- 2021韩顺平图解Linux课程(全面升级)基础篇
第1章 Linux 开山篇-内容介绍 本套 Linux 课程内容 Linux 主要应用领域:服务器 第2章 Linux 基础篇-Linux 入门 Linux 之父 Linus Torvalds Git ...
- C# 9 新特性 —— 增强的 foreach
C# 9 新特性 -- 增强的 foreach Intro 在 C# 9 中增强了 foreach 的使用,使得一切对象都有 foreach 的可能 我们来看一段代码,这里我们试图遍历一个 int 类 ...
- 轻松上手CSS Grid网格布局
今天刚好要做一个好多div格子错落组成的布局,不是田字格,不是九宫格,12个格子这样子,看起来有点复杂.关键的是笔者有点懒,要写那么多div和css真是不想下手啊.多看了两眼,这布局不跟网格挺像吗?c ...
- [LeetCode]319. Bulb Switcher灯泡开关
智商压制的一道题 这个题有个数学定理: 一般数(非完全平方数)的因子有偶数个 完全平凡数的因子有奇数个 开开关的时候,第i个灯每到它的因子一轮的时候就会拨动一下,也就是每个灯拨动的次数是它的因子数 而 ...
- Plugin 插件体系
Solon 的插件也可以叫扩展组件,相当于Spring 的 starter.Solon已经提供了大量的基础插件,但对第三方的框架适配目前较少. 插件 说明 boot插件:: 说明 org.noear: ...