• 实现客户端程序自动更新使用FTP


     最近做的一个项目中需要用到客户端自动更新功能,最初的想法是利用ClickOnce技术来完成,但在实践中发现根本行不能,原因如下:

    1)项目应用到了DevExpress控件包,用ClickOnce发布的自动更新程序,客户在安装时报在GAC中找不到控件dll的错。

    2)ClickOnce安装无法实现根据用户安装时录入的参数(比如数据库服务器名、数据库用户名和密码等)来动态修改配置文件的功能。

    3)最后一下其实不重要了,就是ClickOnce无法实现用户自定义安装文件夹。

      最后决定放弃使用ClickOnce,使用ftp方式进行,实现思路如下:用户启动程序时,先运行update.exe,该文件会自动比较本地配置文件和ftp服务器上配置文件的异同,会自动下载上次更新后变化的文件以及新加入的文件。(因为都是基本配置文件,所以开发了一个配置文件生成工具,用户只需要选择根目录后,就会自动生成配置文件。)文件下载结束后,再启动实际的客户端程序。

      程序的主要代码如:

    1using System;
      2using System.Collections.Generic;
      3using System.Diagnostics;
      4using System.IO;
      5using System.Net;
      6using System.Threading;
      7using System.Windows.Forms;
      8
      9namespace Update
     10{
     11    /// <summary>
     12    /// Description: 
     13    /// Author: ZhangRongHua
     14    /// Create DateTime: 2009-6-21 12:25
     15    /// UpdateHistory:      
     16    /// </summary>

     17    public partial class frmUpdate : Form
     18    {
     19        #region Fields
     20
     21        private const string CONFIGFILE = "update.xml";
     22        private const string UPDATEDIR = "PMS";
     23        private string appPath = Application.StartupPath;
     24        private List<ErrorInfo> errorList = new List<ErrorInfo>();
     25        private string locFile = String.Concat(Application.StartupPath, "\\", CONFIGFILE);
     26        private string tmpUpdateFile = "TmpUpdate.xml";
     27        private List<string> updateList;
     28        private string updateTmpPath = string.Concat(Path.GetTempPath(), "\\", UPDATEDIR);   
     29        private string url = String.Empty;
     30
     31        private FTP ftp = null;
     32
     33        #endregion

     34
     35        #region Delegates
     36
     37        public delegate void AsycDownLoadFile(string srcFile, string destFile, int i);
     38
     39        public delegate void ExecuteUpdateFiles(string srcPath, string destPath);
     40
     41        public delegate void UpdateComplete();
     42
     43        public delegate void UpdateUI(int i, string message);
     44
     45        #endregion

     46
     47        public event UpdateComplete OnUpdateComplete;
     48
     49        #region Constructor
     50
     51        public frmUpdate()
     52        {
     53            InitializeComponent();
     54            OnUpdateComplete += new UpdateComplete(frmUpdate_OnUpdateComplete);
     55        }

     56
     57        #endregion

     58
     59        #region Event Handler
     60
     61        private void frmUpdate_Load(object sender, EventArgs e)
     62        {
     63           if(Directory.Exists(updateTmpPath))
     64           {
     65               Directory.Delete(updateTmpPath, true);
     66           }

     67         
     68            // 如果有主程序启动,则关闭
     69            Process[] ps = Process.GetProcesses();
     70            foreach (Process p in ps)
     71            {
     72                //MessageBox.Show(p.ProcessName);
     73                if (p.ProcessName.ToLower() == "wat.pms.winform")
     74                {
     75                    p.Kill();
     76                    break;
     77                }

     78            }

     79
     80            GetUpdateFiles();
     81        }

     82
     83        private void frmUpdate_OnUpdateComplete()
     84        {
     85            ExecuteUpdateFiles dExecuteUpdateFiles = new ExecuteUpdateFiles(ExecuteUpdate);
     86            Invoke(dExecuteUpdateFiles, new object[] {updateTmpPath, appPath});
     87        }

     88
     89        private void frmUpdate_Shown(object sender, EventArgs e)
     90        {
     91            Thread updateThread = new Thread(new ThreadStart(DownLoadUpdateFiles));
     92            updateThread.SetApartmentState(ApartmentState.STA);
     93            updateThread.IsBackground = true;
     94            Thread.Sleep(500);
     95            updateThread.Start();
     96
     97  
     98         }

     99
    100        #endregion

    101
    102        #region Private Methods
    103
    104         /// <summary>
    105         /// 将目标文件替换为本地文件
    106         /// <remark> 
    107         /// Author:ZhangRongHua 
    108         /// Create DateTime: 2009-6-21 10:28
    109         /// Update History:     
    110         ///  </remark>
    111         /// </summary>
    112         /// <param name="srcFile">The SRC file.</param>
    113         /// <param name="destFile">The dest file.</param>

    114        private void DownLoadFile(string srcFile, string destFile)
    115        {
    116            if(ftp == null )
    117            {
    118                ftp = new FTP(Updater.URL, "", Updater.User, Updater.Password);
    119            }

    120
    121           
    122
    123            if(!ftp.Connected)
    124            {
    125                MessageBox.Show("无法连接远程服务器,无法更新程序""提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
    126                Process.Start(Updater.MainProgram);
    127                Close();
    128                
    129            }

    130
    131            // 得到服务器端的配置文件
    132             ftp.Get(srcFile, updateTmpPath, destFile);
    133
    134          
    135 
    136        }

    137
    138        /// <summary>
    139        /// 得到需要更新的文件清单
    140        /// <remark> 
    141        /// Author:ZhangRongHua 
    142        /// Create DateTime: 2009-6-21 10:29
    143        /// Update History:     
    144        ///  </remark>
    145        /// </summary>

    146        private void GetUpdateFiles()
    147        {
    148            Updater.GetBaseInfo(locFile);
    149            url = Updater.URL;
    150            string svrFile = String.Concat(url, CONFIGFILE);
    151
    152            if (String.IsNullOrEmpty(svrFile))
    153            {
    154                BroadCastOnUpdateComplete();
    155                return;
    156            }

    157
    158            Directory.CreateDirectory(updateTmpPath);
    159            try
    160            {
    161                DownLoadFile(CONFIGFILE, tmpUpdateFile);
    162            }

    163            catch (Exception ex)
    164            {
    165                MessageBox.Show("无法连接远程服务器,无法更新程序""提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
    166                Process.Start(Updater.MainProgram);
    167                Close();
    168            }

    169
    170            updateList = Updater.GetUpdateFileList(locFile, tmpUpdateFile);
    171            if (updateList == null || updateList.Count < 1)
    172            {
    173                BroadCastOnUpdateComplete();
    174                return;
    175            }

    176
    177            pbUpdate.Maximum = updateList.Count;
    178            pbUpdate.Minimum = 0;
    179            lblInfo.Text = String.Concat(updateList.Count, "个文件需要更新!");
    180            lblInfo.BringToFront();
    181            lblState.BringToFront();
    182            lblInfo.Update();
    183
    184            pbUpdate.Maximum = updateList.Count;
    185            pbUpdate.Minimum = 0;
    186
    187            for (int i = 0; i < updateList.Count; i++)
    188            {
    189                string file = updateList[i];
    190                ListViewItem lvItem = new ListViewItem();
    191                lvItem.Text = file;
    192                lvItem.SubItems.Add(Updater.MainProgramVersion);
    193                lvUpdateList.Items.Add(lvItem);
    194            }

    195        }

    196
    197        private void UpdateUIInfo(int i, string message)
    198        {
    199            pbUpdate.Value = i + 1;
    200            lblState.Text = message;
    201            lblState.Update();
    202        }

    203
    204        private void BroadCastOnUpdateComplete()
    205        {
    206            if (OnUpdateComplete != null)
    207            {
    208                OnUpdateComplete();
    209            }

    210        }

    211
    212        private void DownLoadUpdateFiles()
    213        {
    214            if (updateList == null || updateList.Count < 1)
    215            {
    216                BroadCastOnUpdateComplete();
    217                return;
    218            }

    219
    220            try
    221            {
    222                UpdateUI dUpdateUI = new UpdateUI(UpdateUIInfo);
    223                AsycDownLoadFile dAsycDownLoadFile = new AsycDownLoadFile(DownLoadFile);
    224                for (int i = 0; i < updateList.Count; i++)
    225                {
    226                    string file = updateList[i];
    227                    string destFile = String.Concat(updateTmpPath, "\\", file);
    228                    string destFileName = destFile.Substring(destFile.LastIndexOf("/"+ 1);
    229                    string srcFile = String.Concat(url, file);
    230                    var srcFileName = file.Trim('/');
    231                    destFile = destFile.Replace("/""\\");
    232                    Directory.CreateDirectory(destFile.Substring(0, destFile.LastIndexOf("\\")));
    233                    string curentFile = String.Concat("正在更新第", i + 1"/", updateList.Count, "", file);
    234                   
    235                    Invoke(dAsycDownLoadFile, new object[] { srcFileName, srcFileName, i });
    236                    Thread.Sleep(50);
    237                    Invoke(dUpdateUI, new object[] {i, curentFile});
    238                }

    239            }

    240            catch (Exception ex)
    241            {
    242                Debug.WriteLine(ex.Message);
    243            }

    244
    245            BroadCastOnUpdateComplete();
    246        }

    247
    248        
    249
    250        private void CopyUpdateFiles(string srcPath, string destPath)
    251        {
    252            string[] files = Directory.GetFiles(srcPath);
    253            for (int i = 0; i < files.Length; i++)
    254            {
    255                string srcFile = files[i];
    256                string destFile = string.Concat(destPath, "\\", Path.GetFileName(srcFile));
    257                try
    258                {
    259                    File.Copy(srcFile, destFile, true);
    260                }

    261                catch (System.IO.IOException  ex)
    262                {
    263                    
    264                    
    265                }

    266                 
    267            }

    268
    269            string[] dirs = Directory.GetDirectories(srcPath);
    270            for (int i = 0; i < dirs.Length; i++)
    271            {
    272                srcPath = dirs[i];
    273                string tmpDestPath = String.Concat(destPath, "\\", Path.GetFileName(srcPath));
    274                Directory.CreateDirectory(tmpDestPath);
    275                CopyUpdateFiles(srcPath, tmpDestPath);
    276            }

    277        }

    278
    279
    280
    281        /// <summary>
    282        /// 更新完成后,要执行的动作(将下载的文件从临时目录复制到主目录,重启主程序)
    283        /// <remark> 
    284        /// Author:ZhangRongHua 
    285        /// Create DateTime: 2009-6-21 12:25
    286        /// Update History:     
    287        ///  </remark>
    288        /// </summary>
    289        /// <param name="srcPath">The SRC path.</param>
    290        /// <param name="destPath">The dest path.</param>

    291        private void ExecuteUpdate(string srcPath, string destPath)
    292        {
    293            if (errorList != null && errorList.Count < 1)
    294            {
    295                lblInfo.Text = "正在执行更新";
    296                lblInfo.Update();
    297                CopyUpdateFiles(srcPath, destPath);
    298                File.Copy(tmpUpdateFile, locFile, true);
    299            }

    300            Process.Start(Updater.MainProgram);
    301
    302            Close();
    303        }

    304
    305        private void DownLoadFile(string srcFile, string destFile, ListViewItem lvItem)
    306        {
    307            try
    308            {
    309                DownLoadFile(srcFile, destFile);
    310                lvItem.SubItems.Add("Ok");
    311             }

    312            catch (Exception ex)
    313            {
    314                Debug.WriteLine(ex.Message);
    315                lvItem.SubItems.Add("fail");
    316                ErrorInfo errorInfo = new ErrorInfo();
    317                errorInfo.File = srcFile;
    318                errorInfo.ErrorLevel = ErrorLevel.Serious;
    319                errorInfo.Message = ex.Message;
    320                errorList.Add(errorInfo);
    321            }

    322        }

    323
    324        private void DownLoadFile(string srcFile, string destFile, int i)
    325        {
    326            ListViewItem lvItem = lvUpdateList.Items[i];
    327
    328            lvUpdateList.Items[i].EnsureVisible();
    329            try
    330            {
    331                DownLoadFile(srcFile, destFile);
    332                lvItem.SubItems.Add("Ok");
    333            }

    334            catch (Exception ex)
    335            {
    336                Debug.WriteLine(ex.Message);
    337                lvItem.SubItems.Add("fail");
    338                ErrorInfo errorInfo = new ErrorInfo();
    339                errorInfo.File = srcFile;
    340                errorInfo.ErrorLevel = ErrorLevel.Serious;
    341                errorInfo.Message = ex.Message;
    342                errorList.Add(errorInfo);
    343                MessageBox.Show(destFile);
    344            }

    345        }

    346
    347        #endregion

    348    }

    349}


    出处:http://zhangronghua.cnblogs.com

  • 相关阅读:
    Vue $nextTick的一个使用场景
    Vue 使用v-for对Object进行遍历
    JavaScript 回调函数的简单示例
    VSCode 自定义Vue snippets, 快速生成Vue模板
    git将一个分支完全覆盖另外一个分支如:dev分支代码完全覆盖某一个开发分支
    解决bootstrap时间输入框总被浏览器记住的记录遮挡住的问题
    Fiddler 屏蔽JS、抓WebSocket协议、查看接口响应时间、模拟并发请求
    细说MySQL的时间戳(Timestamp)类型
    网站建设之域名注册和域名备案
    日常项目测试用例检查点(来自一线测试人员的吐血总结)
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/1836966.html
Copyright © 2020-2023  润新知