实现客户端程序自动更新使用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

原文地址:https://www.cnblogs.com/Leo_wl/p/1836966.html