c#开发c/s端过程中,经常遇到需要程序自动更新的功能,在这里我分享一个自己写的自动更新程序;此自动更新程序支持失败回滚操作,用到的技术也比较简单无非就是xml文件读写http文件下载

开源地址:https://github.com/zonevg/AutoUpdater

c# 自动更新程序

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Net;
using System.IO;
using System.Diagnostics;
using System.Xml;

namespace AutoUpdater
{
    public partial class FrmDownloadProgress : Form
    {
        private List<DownloadFileInfo> downloadFileList = null;
        private List<DownloadFileInfo> allFileList = null;
        private ManualResetEvent evtDownload = null;
        private ManualResetEvent evtPerDonwload = null;
        private WebClient clientDownload = null;
        private long total = 0;
        private long nDownloadedTotal = 0;
        private delegate void ShowCurrentDownloadFileNameCallBack(string name,long size);
        private delegate void SetProcessBarCallBack(int current, int total);

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="downloadFileListTemp"></param>
        public FrmDownloadProgress(List<DownloadFileInfo> downloadFileListTemp)
        {
            InitializeComponent();

            //初始化要下载的文件 
            this.downloadFileList = downloadFileListTemp;
            allFileList = new List<DownloadFileInfo>();
            foreach (DownloadFileInfo file in downloadFileListTemp)
            {
                allFileList.Add(file);
            }
        }

        /// <summary>
        /// 窗口关闭事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnFormClosing(object sender, FormClosingEventArgs e)
        {
            if (clientDownload != null)
                clientDownload.CancelAsync();

            evtDownload.Set();
            evtPerDonwload.Set();
        }

        /// <summary>
        /// 窗口加载事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnFormLoad(object sender, EventArgs e)
        {
            evtDownload = new ManualResetEvent(true);
            evtDownload.Reset();
            ThreadPool.QueueUserWorkItem(new WaitCallback(this.ProcDownload));
        }

        /// <summary>
        /// 下载文件
        /// </summary>
        /// <param name="o"></param>
        private void ProcDownload(object o)
        {
            try
            {
                //获取临时文件夹目录
                string tempFolderPath = Path.Combine(CommonUnitity.SystemBinUrl, ConstFile.TEMPFOLDERNAME);
                if (!Directory.Exists(tempFolderPath))
                {
                    Directory.CreateDirectory(tempFolderPath);
                }

                evtPerDonwload = new ManualResetEvent(false);

                //获取文件总大小
                foreach (DownloadFileInfo file in this.downloadFileList)
                {
                    total += file.Size;
                }


                //循环下载
                while (!evtDownload.WaitOne(0, false))
                {
                    if (this.downloadFileList.Count == 0)
                        break;

                    //取得下载文件信息
                    DownloadFileInfo file = this.downloadFileList[0];
                    //在UI呈现当前任务信息
                    this.ShowCurrentDownloadFileName(file.FileName, file.Size);
                    //创建网络连接
                    clientDownload = new WebClient();
                    //使用系统代理
                    clientDownload.Proxy = WebRequest.GetSystemWebProxy();
                    //使用应用程序凭据
                    clientDownload.Proxy.Credentials = CredentialCache.DefaultCredentials;
                    //使用应用程序凭据
                    clientDownload.Credentials = System.Net.CredentialCache.DefaultCredentials;
                    //文件下载进度更新
                    clientDownload.DownloadProgressChanged += (object sender, DownloadProgressChangedEventArgs e) =>
                    {
                        try
                        {
                            this.SetProcessBar(e.ProgressPercentage, (int)((nDownloadedTotal + e.BytesReceived) * 100 / total));
                        }
                        catch { }

                    };

                    //文件下载完成
                    clientDownload.DownloadFileCompleted += (object sender, AsyncCompletedEventArgs e) =>
                    {
                        try
                        {
                            //验证网络是否正常
                            DealWithDownloadErrors();
                            DownloadFileInfo dfile = e.UserState as DownloadFileInfo;
                            nDownloadedTotal += dfile.Size;
                            this.SetProcessBar(0, (int)(nDownloadedTotal * 100 / total));
                            //标记已完成
                            evtPerDonwload.Set();
                        }
                        catch { }

                    };
                    //阻隔线程
                    evtPerDonwload.Reset();
                    //创建文件保存路径
                    string tempFolderPath1 = CommonUnitity.GetFolderUrl(file);
                    if (!string.IsNullOrEmpty(tempFolderPath1))
                    {
                        tempFolderPath = Path.Combine(CommonUnitity.SystemBinUrl, ConstFile.TEMPFOLDERNAME);
                        tempFolderPath += tempFolderPath1;
                    }
                    else
                    {
                        tempFolderPath = Path.Combine(CommonUnitity.SystemBinUrl, ConstFile.TEMPFOLDERNAME);
                    }

                    //开始下载文件
                    clientDownload.DownloadFileAsync(new Uri(file.DownloadUrl), Path.Combine(tempFolderPath, file.FileName), file);
                    //等待任务完成
                    evtPerDonwload.WaitOne();
                    //销毁下载对象
                    clientDownload.Dispose();
                    clientDownload = null;
                    //移除已下载的文件
                    this.downloadFileList.Remove(file);
                }

                //如果没有下载文件,返回
                if (downloadFileList.Count > 0)
                    return;

                //处理网络错误
                //DealWithDownloadErrors();
                //拷贝文件到程序目录
                foreach (DownloadFileInfo file in this.allFileList)
                {
                    string tempUrlPath = CommonUnitity.GetFolderUrl(file);
                    string destFileName = string.Empty;
                    string sourceFileName = string.Empty;
                    try
                    {
                        //生成源路径与目标路径
                        if (!string.IsNullOrEmpty(tempUrlPath))
                        {
                            destFileName = Path.Combine(CommonUnitity.SystemBinUrl + tempUrlPath.Substring(1), file.FileName);
                            sourceFileName = Path.Combine(CommonUnitity.SystemBinUrl + ConstFile.TEMPFOLDERNAME + tempUrlPath, file.FileName);
                        }
                        else
                        {
                            destFileName = Path.Combine(CommonUnitity.SystemBinUrl, file.FileName);
                            sourceFileName = Path.Combine(CommonUnitity.SystemBinUrl + ConstFile.TEMPFOLDERNAME, file.FileName);
                        }

                        //验证文件是否损坏
                        System.IO.FileInfo f = new FileInfo(sourceFileName);
                        if (!file.Size.ToString().Equals(f.Length.ToString()) && !file.FileName.ToString().EndsWith(".xml"))
                        {
                            ShowErrorAndRestartApplication();
                        }

                        string newfilepath = string.Empty;
                        if (sourceFileName.Substring(sourceFileName.LastIndexOf(".") + 1).Equals(ConstFile.CONFIGFILEKEY))
                        {
                            if (System.IO.File.Exists(sourceFileName))
                            {
                                if (sourceFileName.EndsWith("_"))
                                {
                                    newfilepath = sourceFileName;
                                    sourceFileName = sourceFileName.Substring(0, sourceFileName.Length - 1);
                                    destFileName = destFileName.Substring(0, destFileName.Length - 1);
                                }
                                File.Move(newfilepath, sourceFileName);
                            }
                        }

                        if (File.Exists(destFileName))
                        {
                            MoveFolderToOld(destFileName, sourceFileName);
                        }
                        else
                        {
                            if (!string.IsNullOrEmpty(tempUrlPath))
                            {
                                if (!Directory.Exists(CommonUnitity.SystemBinUrl + tempUrlPath.Substring(1)))
                                {
                                    Directory.CreateDirectory(CommonUnitity.SystemBinUrl + tempUrlPath.Substring(1));


                                    MoveFolderToOld(destFileName, sourceFileName);
                                }
                                else
                                {
                                    MoveFolderToOld(destFileName, sourceFileName);
                                }
                            }
                            else
                            {
                                MoveFolderToOld(destFileName, sourceFileName);
                            }

                        }
                    }
                    catch
                    {
                        ShowErrorAndRestartApplication();
                    }

                }
                this.allFileList.Clear();
                if (this.downloadFileList.Count == 0)
                    this.DialogResult = DialogResult.OK;
                else
                    this.DialogResult = DialogResult.Cancel;
                evtDownload.Set();
            }
            catch
            {
                ShowErrorAndRestartApplication();
            }
        }

        /// <summary>
        /// 将下载完成的文件移动到指定位置
        /// </summary>
        /// <param name="destFileName"></param>
        /// <param name="sourceFileName"></param>
        void MoveFolderToOld(string destFileName, string sourceFileName)
        {
            if (File.Exists(destFileName + ".old"))
                File.Delete(destFileName + ".old");

            if (File.Exists(destFileName))
                File.Move(destFileName, destFileName + ".old");

            File.Move(sourceFileName, destFileName);
            //File.Delete(oldPath + ".old");
        }

        /// <summary>
        /// 显示正在下载的文件
        /// </summary>
        /// <param name="name"></param>
        private void ShowCurrentDownloadFileName(string name,long size)
        {
            if (this.lblFileName.InvokeRequired)
            {
                ShowCurrentDownloadFileNameCallBack cb = new ShowCurrentDownloadFileNameCallBack(ShowCurrentDownloadFileName);
                this.Invoke(cb, new object[] { name,size });
            }
            else
            {
                this.lblFileName.Text = $"文件信息:{name}({size / 1024}KB)";
            }
        }

        /// <summary>
        /// 更新进度条
        /// </summary>
        /// <param name="current"></param>
        /// <param name="total"></param>
        private void SetProcessBar(int current, int total)
        {
            if (this.progressBarCurrent.InvokeRequired)
            {
                SetProcessBarCallBack cb = new SetProcessBarCallBack(SetProcessBar);
                this.Invoke(cb, new object[] { current, total });
            }
            else
            {
                this.progressBarCurrent.Value = current;
                this.progressBarTotal.Value = total;
            }
        }

        /// <summary>
        /// 处理网络错误
        /// </summary>
        private void DealWithDownloadErrors()
        {
            try
            {
                //检测网络是否联通
                Config config = Config.LoadConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConstFile.FILENAME));
                WebClient client = new WebClient();
                client.DownloadString(config.ServerUrl);
            }
            catch 
            {
                ShowErrorAndRestartApplication();
            }
        }

        /// <summary>
        /// 更新遇到问题提示重试
        /// </summary>
        private void ShowErrorAndRestartApplication()
        {
            MessageBox.Show(ConstFile.NOTNETWORK, ConstFile.MESSAGETITLE, MessageBoxButtons.OK, MessageBoxIcon.Information);
            this.DialogResult = DialogResult.Cancel;
        }

        private void lblSdgx_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            Process.Start($"http://www.sotoolbox.com/packet/mainApp.zip");
        }
    }
}
最后修改:2022 年 09 月 29 日
如果觉得我的文章对你有用,请随意赞赏