C#程序自动更新功能

思路:
1.在后端接口项目中配置程序的最新版本,并在程序的配置中配置当前版本。
2.在程序启动时,向后端请求获取最新版本接口,并匹配程序配置中的当前版本。
3.若不匹配,则表示不是最新版本,需要更新。这时,再次像后端请求获取最新程序的安装包接口(压缩包文件),并直接解压到程序根目录,替换需要的文件。(程序不能直接替换和删除正在运行的文件,但是可以重命名正在运行的文件,并且还可以修改后缀。所以,可以考虑先把需要被替换的文件重命名其他名称,然后再直接将压缩包文件解压到指定文件夹,达到被替换的效果)。
4.最后,可以直接重新启动程序。

代码:
1.创建窗体(显示更新信息的窗体)
在这里插入图片描述

2.窗口控件的代码:

private void InitializeComponent()
{
    System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(UpdateAppForm));
    this.rtBoxMsg = new System.Windows.Forms.RichTextBox();
    this.picBoxState = new System.Windows.Forms.PictureBox();
    this.label1 = new System.Windows.Forms.Label();
    ((System.ComponentModel.ISupportInitialize)(this.picBoxState)).BeginInit();
    this.SuspendLayout();
    // 
    // rtBoxMsg
    // 
    this.rtBoxMsg.BackColor = System.Drawing.SystemColors.Info;
    this.rtBoxMsg.Location = new System.Drawing.Point(8, 26);
    this.rtBoxMsg.Name = "rtBoxMsg";
    this.rtBoxMsg.Size = new System.Drawing.Size(511, 213);
    this.rtBoxMsg.TabIndex = 13;
    this.rtBoxMsg.Text = "";
    // 
    // picBoxState
    // 
    this.picBoxState.Image = ((System.Drawing.Image)(resources.GetObject("picBoxState.Image")));
    this.picBoxState.Location = new System.Drawing.Point(10, 4);
    this.picBoxState.Name = "picBoxState";
    this.picBoxState.Size = new System.Drawing.Size(16, 16);
    this.picBoxState.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
    this.picBoxState.TabIndex = 16;
    this.picBoxState.TabStop = false;
    // 
    // label1
    // 
    this.label1.AutoSize = true;
    this.label1.Location = new System.Drawing.Point(30, 6);
    this.label1.Name = "label1";
    this.label1.Size = new System.Drawing.Size(149, 12);
    this.label1.TabIndex = 15;
    this.label1.Text = "程序检查更新中,请勿关闭";
    // 
    // UpdateAppForm
    // 
    this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
    this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    this.BackColor = System.Drawing.SystemColors.Control;
    this.ClientSize = new System.Drawing.Size(526, 247);
    this.Controls.Add(this.picBoxState);
    this.Controls.Add(this.label1);
    this.Controls.Add(this.rtBoxMsg);
    this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
    this.Name = "UpdateAppForm";
    this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
    this.Text = "更新程序";
    this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.UpdateAppForm_FormClosing);
    this.Load += new System.EventHandler(this.UpdateAppForm_Load);
    ((System.ComponentModel.ISupportInitialize)(this.picBoxState)).EndInit();
    this.ResumeLayout(false);
    this.PerformLayout();

}

3.加载主程序之前先加载更新检测功能
在这里插入图片描述

4.更新检测代码:
在这里插入图片描述

using log4net;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using 智慧工地大屏.Ext;
using 智慧工地大屏.Model;
using 智慧工地大屏.UpdateAppUtil;
using 智慧工地大屏.util;

namespace 智慧工地大屏.UpdateApp
{
    public partial class UpdateAppForm : Form
    {
        private static ILog logger = LogManager.GetLogger(typeof(UpdateAppForm));

        // 数据交互处理
        SocketClient_Kenel s_client = null;

        // 多长时间检测一次版本号
        int checkVersionTimer = 1800;

        // 刷新线程
        Thread thrRefresher1;
        // 线程同步锁
        bool bSignAlive = true;

        private AutoUpdateHelper.DelegateSetUpdateInfo DelegateSetUpdateInfo = null;
        private AutoUpdateHelper AutoUpdateHelper = null;

        public UpdateAppForm()
        {
            InitializeComponent();
            DelegateSetUpdateInfo = new AutoUpdateHelper.DelegateSetUpdateInfo(setUpdateInfo);
            AutoUpdateHelper = new AutoUpdateHelper(DelegateSetUpdateInfo);
        }

        private void UpdateAppForm_Load(object sender, EventArgs e)
        {
            setUpdateInfo("正在加载当前程序更新服务...");

            // 删除exe旧文件
            if (File.Exists(AppDomain.CurrentDomain.BaseDirectory + "\\exe_old.txt"))
            {
                File.Delete(AppDomain.CurrentDomain.BaseDirectory + "\\exe_old.txt");
            }

            // 删除config旧文件
            if (File.Exists(AppDomain.CurrentDomain.BaseDirectory + "\\config\\Config_old.xml"))
            {
                File.Delete(AppDomain.CurrentDomain.BaseDirectory + "\\config\\Config_old.xml");
            }

            // 开启数据接收服务
            startServer();

            setUpdateInfo("正在启动当前程序更新服务...");
            // 读取配置文件版本检测时间
            checkVersionTimer = int.Parse(SysContent.tabOneConfigDic["checkVersionTimer"]);
            // 开启消息定时接收线程
            thrRefresher1 = new Thread(new ThreadStart(KeepOnRefreshData));
            thrRefresher1.Start();
        }

        private void UpdateAppForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            // 关闭线程
            bSignAlive = false;
            if (thrRefresher1 != null)
            {
                thrRefresher1.Abort();
            }
        }

        /// <summary>
        /// 关闭方法的委托
        /// </summary>
        /// <param name="versionNum"></param>
        /// <returns></returns>
        public delegate void CloseMethodDelegate(string versionNum);

        /// <summary>
        /// 启动服务
        /// </summary>
        public void startServer()
        {
            string[] ipAdd = SysContent.tabOneConfigDic["serverUrl"].ToString().Split(':');
            s_client = new SocketClient_Kenel(new[] { ipAdd[0], ipAdd[1] });

            s_client.Init();
            Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    Thread.Sleep(1);
                    if (!s_client.q_rec.IsEmpty) //队列不为空则取出
                    {
                        s_client.q_rec.TryDequeue(out byte[] data);
                        //解析data
                        string res = Encoding.UTF8.GetString(data);
                        if (!string.IsNullOrWhiteSpace(res))
                        {
                            logger.Info("@智慧工地返回信息:" + res);
                            try
                            {
                                BaseResponse baseResponse = util.JsonHelper.DeserializeJsonToObject<BaseResponse>(res);
                                if (baseResponse != null && baseResponse.code == MethodState.successCode)
                                {
                                    string json = util.JsonHelper.SerializeObject(baseResponse.data);
                                    if (baseResponse.txCode == MethodState.TransCode.TRANS_CODE_5102)
                                    {
                                        RequestSaas projectOverviewInfoInfo = util.JsonHelper.DeserializeJsonToObject<RequestSaas>(json);
                                        BeginInvoke(new CloseMethodDelegate(autoUpdate), projectOverviewInfoInfo.versionNum.Trim());
                                    }
                                }
                                else
                                {
                                    logger.Error("接收无效信息...");
                                }
                            }
                            catch (Exception e)
                            {
                                logger.Error("接收错误", e);
                            }
                        }
                    }
                }
            }, TaskCreationOptions.LongRunning);
        }

        /// <summary>
		/// 隔一段时间检测一次版本
		/// </summary>
		private void KeepOnRefreshData()
        {
            while (true)
            {
                //如果外部窗体关闭,则从内部终止线程
                if (!bSignAlive)
                {
                    break;
                }
                s_client.SendScsMessage(MethodState.TransCode.TRANS_CODE_5102, "", "");
                Thread.Sleep(1000 * checkVersionTimer);
            }
        }

        /// <summary>
        /// 更新程序
        /// versionNum 最新版本号
        /// </summary>
        private void autoUpdate(string _newsVersion)
        {
            try
            {
                setUpdateInfo("正在读取当前程序信息...");
                // 当前版本号
                string _nowVersion = SysContent.tabOneConfigDic["version"];
                setUpdateInfo("正在检查是否需要更新...");
                if (!string.Equals(_nowVersion, _newsVersion))
                {
                    setUpdateInfo("发现新版本,是否更新?");
                    if (DialogResult.OK == MessageBox.Show("发现新版本!是否更新?", "新版本", MessageBoxButtons.OKCancel, MessageBoxIcon.Question))
                    {
                        // 下载程序文件
                        if (AutoUpdateHelper.DoenloadUpdateFile())
                        {
                            // 替换新程序
                            if (AutoUpdateHelper.ReplaceFile())
                            {
                                MessageBox.Show("更新完成,确认重启程序");
                                // 重启主程序
                                Restart();
                            }
                        }
                    }
                    else
                    {
                        this.Close();
                    }
                }
                else
                {
                    setUpdateInfo("当前版本已是最新版本,无需更新");
                    this.Close();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        /// <summary>
        /// 更新完成之后重新启动该程序
        /// </summary>
        public static void Restart()
        {
            //开启新的实例
            Process.Start(Application.ExecutablePath);

            //关闭当前实例
            Process.GetCurrentProcess().Kill();
        }

        public delegate void DelegateShowMsg(string msg);

        /// <summary>
        /// 给信息数据委托赋值
        /// </summary>
        /// <param name="msg"></param>
        private void setUpdateInfo(string msg)
        {
            try
            {
                if (this.InvokeRequired)
                {
                    this.Invoke(new DelegateShowMsg(setUpdateInfo), new object[] { msg });
                    return;
                }
                this.rtBoxMsg.AppendText(msg + "\r\n");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }


        
    }
}

5.下载文件代码
在这里插入图片描述
在这里插入图片描述

using log4net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Xml;
using 智慧工地大屏.Model;
using 智慧工地大屏.util;

namespace 智慧工地大屏.UpdateAppUtil
{
    /// <summary>
    /// 自动更新
    /// </summary>
    public class AutoUpdateHelper
    {
        private static ILog logger = LogManager.GetLogger(typeof(AutoUpdateHelper));
        // 文件下载保存路径
        private string _downLoadSaveTempPath = AppDomain.CurrentDomain.BaseDirectory + "downloadFile\\";

        public delegate void DelegateSetUpdateInfo(string info);
        // 显示信息
        private DelegateSetUpdateInfo setUpdateInfo;
        public AutoUpdateHelper(DelegateSetUpdateInfo setUpdateInfo)
        {
            this.setUpdateInfo = setUpdateInfo;
        }

        /// <summary>
        /// 下载程序文件
        /// </summary>
        /// <returns></returns>
        public bool DoenloadUpdateFile()
        {
            try
            {
                if (!Directory.Exists(_downLoadSaveTempPath))
                {
                    Directory.CreateDirectory(_downLoadSaveTempPath);
                }
                string fileName = SysContent.tabOneConfigDic["downloadFileName"];
                setUpdateInfo("正在下载文件:" + fileName);
                string downFileUrl = SysContent.tabOneConfigDic["webUpdateUrl"] + "saasBigScreen.zip"; ;
                _downLoadSaveTempPath += "saasBigScreen.zip";
                logger.Info("开始下载文件...");
                AutoUpdateWebServiceHelper.DownloadClientFile(downFileUrl, _downLoadSaveTempPath);
                setUpdateInfo("下载完成");
            }
            catch (Exception ex)
            {
                setUpdateInfo("下载更新文件出错" + ex.Message);
                return false;
            }
            return true;
        }

        /// <summary>
        /// 替换文件
        /// </summary>
        public bool ReplaceFile()
        {
            Thread.Sleep(500);
            setUpdateInfo("正在替换文件.....");
            try
            {
                // 重命名主程序(无法删除和替换正在运行的程序,但是可以重命名正在运行的程序)
                string target = @"" + AppDomain.CurrentDomain.BaseDirectory + "\\智慧工地大屏.exe";
                string fileName = "智慧工地大屏.exe";
                string fileDirectory = Path.GetDirectoryName(target);
                string suffix = Path.GetExtension(target);
                string newFileNmae = "exe_old.txt";
                string oldFileName = fileDirectory + "\\" + newFileNmae;
                // 先删除旧文件
                if (File.Exists(oldFileName))
                {
                    File.Delete(oldFileName);
                }

                // 重命名文件为程序文件
                if (File.Exists(target))
                {
                    File.Move(fileDirectory + "\\" + fileName, oldFileName);
                }

                Thread.Sleep(100);

                // 先删除旧文件
                if (File.Exists(fileDirectory + "\\Config.xml"))
                {
                    File.Delete(fileDirectory + "\\Config.xml");
                }
                // 解压下载的文件夹
                ZipHandler.UnZip(fileDirectory+ "\\downloadFile\\saasBigScreen.zip", fileDirectory, "");

                Thread.Sleep(100);
                // 如果根文件夹中存在Config配置文件,将Config配置文件移到所在文件夹中
                // 重命名
                if (File.Exists(fileDirectory + "\\config\\Config.xml"))
                {
                    File.Move(fileDirectory + "\\config\\Config.xml", fileDirectory + "\\config\\Config_old.xml");
                }
                // 移动
                if (File.Exists(fileDirectory + "\\Config.xml"))
                {
                    File.Move(fileDirectory + "\\Config.xml", fileDirectory + "\\config\\Config.xml");
                }

                /*// 解压文件到根目录
                Thread.Sleep(100);
                string folderToZip = _downLoadSaveTempPath;
                string tarPath = AppDomain.CurrentDomain.BaseDirectory;
                ZipHandler.UnZipFile(folderToZip, tarPath);*/
            }
            catch (Exception ex)
            {
                setUpdateInfo("替换文件时出错" + ex.Message);
                return false;
            }
            Thread.Sleep(500);
            setUpdateInfo("更新完成,启动程序...");
            return true;
        }
    }
}

using log4net;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using 智慧工地大屏.Model;
using 智慧工地大屏.util;

namespace 智慧工地大屏.UpdateAppUtil
{
    public class AutoUpdateWebServiceHelper
    {
        private static ILog logger = LogManager.GetLogger(typeof(AutoUpdateWebServiceHelper));

        /// <summary>
        /// 下载文件
        /// </summary>
        /// <param name="url"></param>
        /// <param name="savePath"></param>
        /// <returns></returns>
        public static bool DownloadClientFile(string url, string savePath)
        {
            logger.Info("进入DownloadClientFile方法...");
            logger.Info("url=" + url);
            logger.Info("savePath=" + savePath);
            bool value = false;
            WebResponse response = null;
            Stream stream = null;
            try
            {
                FileStream writeStream; // 写入本地文件流对象
                writeStream = new FileStream(savePath, FileMode.Create);// 文件不保存创建一个文件
                HttpWebRequest myRequest = (HttpWebRequest)HttpWebRequest.Create(url);// 打开网络连接

                Stream readStream = myRequest.GetResponse().GetResponseStream();// 向服务器请求,获得服务器的回应数据流

                byte[] btArray = new byte[512];// 定义一个字节数据,用来向readStream读取内容和向writeStream写入内容
                int contentSize = readStream.Read(btArray, 0, btArray.Length);// 向远程文件读第一次

                while (contentSize > 0)// 如果读取长度大于零则继续读
                {
                    writeStream.Write(btArray, 0, contentSize);// 写入本地文件
                    contentSize = readStream.Read(btArray, 0, btArray.Length);// 继续向远程文件读取
                }

                //关闭流
                writeStream.Close();
                readStream.Close();
            }
            catch (Exception ex)
            {
                logger.Error("下载失败:" + ex);
            }
            finally
            {
                if (stream != null) stream.Close();
                if (response != null) response.Close();
            }
            return value;
        }
    }
}

6.文件解压缩代码

using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace 智慧工地大屏.UpdateAppUtil
{
    public class ZipHandler
    {
        public static void ZipDirectory(string folderToZip, string zipedFileName)
        {
            ZipDirectory(folderToZip, zipedFileName, string.Empty, true, string.Empty, string.Empty, true);
        }

        public static void ZipDirectory(string folderToZip, string zipedFileName, string password)
        {
            ZipDirectory(folderToZip, zipedFileName, password, true, string.Empty, string.Empty, true);
        }

        /// <summary>
        /// 压缩文件夹
        /// </summary>
        /// <param name="folderToZip">需要压缩的文件夹</param>
        /// <param name="zipedFileName">压缩后的Zip完整文件名(如D:\test.zip)</param>
        /// <param name="isRecurse">如果文件夹下有子文件夹,是否递归压缩</param>
        /// <param name="password">解压时需要提供的密码</param>
        /// <param name="fileRegexFilter">文件过滤正则表达式</param>
        /// <param name="directoryRegexFilter">文件夹过滤正则表达式</param>
        /// <param name="isCreateEmptyDirectories">是否压缩文件中的空文件夹</param>
        public static void ZipDirectory(string folderToZip, string zipedFileName, string password, bool isRecurse, string fileRegexFilter, string directoryRegexFilter, bool isCreateEmptyDirectories)
        {
            FastZip fastZip = new FastZip();
            fastZip.CreateEmptyDirectories = isCreateEmptyDirectories;
            fastZip.Password = password;
            fastZip.CreateZip(zipedFileName, folderToZip, isRecurse, fileRegexFilter, directoryRegexFilter);
        }

        public static void UnZipFile(string zipedFileName, string targetDirectory)
        {
            UnZipFile(zipedFileName, targetDirectory, string.Empty, string.Empty);
        }

        public static void UnZipFile(string zipedFileName, string targetDirectory, string password)
        {
            UnZipFile(zipedFileName, targetDirectory, password, string.Empty);
        }


        /// <summary>
        /// 解压缩文件
        /// </summary>
        /// <param name="zipedFileName">Zip的完整文件名(如D:\test.zip)</param>
        /// <param name="targetDirectory">解压到的目录</param>
        /// <param name="password">解压密码</param>
        /// <param name="fileFilter">文件过滤正则表达式</param>
        public static void UnZipFile(string zipedFileName, string targetDirectory, string password, string fileFilter)
        {
            FastZip fastZip = new FastZip();
            fastZip.Password = password;
            fastZip.ExtractZip(zipedFileName, targetDirectory, fileFilter);
        }

        /// <summary>   
        /// 解压功能   
        /// </summary>   
        /// <param name="fileToUnZip">待解压的文件</param>   
        /// <param name="zipedFolder">指定解压目标目录</param>   
        /// <param name="password">密码</param>   
        /// <returns>解压结果</returns>   
        public static bool UnZip(string fileToUnZip, string zipedFolder, string password)
        {
            bool result = true;
            FileStream fs = null;
            ZipInputStream zipStream = null;
            ZipEntry ent = null;
            string fileName;

            if (!File.Exists(fileToUnZip))
            {
                return false;
            }

            if (!Directory.Exists(zipedFolder))
            { 
                Directory.CreateDirectory(zipedFolder); 
            }

            try
            {
                zipStream = new ZipInputStream(File.OpenRead(fileToUnZip.Trim()));
                if (!string.IsNullOrEmpty(password)) { zipStream.Password = password; }
                while ((ent = zipStream.GetNextEntry()) != null)
                {
                    if (!string.IsNullOrEmpty(ent.Name))
                    {
                        fileName = Path.Combine(zipedFolder, ent.Name);
                        fileName = fileName.Replace('/', '\\');

                        if (fileName.EndsWith("\\"))
                        {
                            Directory.CreateDirectory(fileName);
                            continue;
                        }

                        using (fs = File.Create(fileName))
                        {
                            int size = 2048;
                            byte[] data = new byte[size];
                            while (true)
                            {
                                size = zipStream.Read(data, 0, data.Length);
                                if (size > 0)
                                    fs.Write(data, 0, size);
                                else
                                    break;
                            }
                        }
                    }
                }
            }
            catch
            {
                result = false;
            }
            finally
            {
                if (fs != null)
                {
                    fs.Close();
                    fs.Dispose();
                }
                if (zipStream != null)
                {
                    zipStream.Close();
                    zipStream.Dispose();
                }
                if (ent != null)
                {
                    ent = null;
                }
                GC.Collect();
                GC.Collect(1);
            }
            return result;
        }

    }
}

上述解压缩文件代码需要使用到第三方工具:
ICSharpCode.SharpZipLib.dll 可以网上下载一个或者从我这下载

  • 2
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哎呦喂O_o嗨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值