lomg 发表于 2015-5-28 12:37:55

实现客户端程序自动更新使用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    /**////
12    /// Description:
13    /// Author: ZhangRongHua
14    /// Create DateTime: 2009-6-21 12:25
15    /// UpdateHistory:      
16    ///
17    public partial class frmUpdate : Form
18    {
19      Fields#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 errorList = new List();
25      private string locFile = String.Concat(Application.StartupPath, "\\", CONFIGFILE);
26      private string tmpUpdateFile = "TmpUpdate.xml";
27      private List 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      Delegates#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      Constructor#region Constructor
50
51      public frmUpdate()
52      {
53            InitializeComponent();
54            OnUpdateComplete += new UpdateComplete(frmUpdate_OnUpdateComplete);
55      }
56
57      #endregion
58
59      Event Handler#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      Private Methods#region Private Methods
103
104         /**////
105         /// 将目标文件替换为本地文件
106         ///
107         /// Author:ZhangRongHua
108         /// Create DateTime: 2009-6-21 10:28
109         /// Update History:   
110         ///
111         ///
112         /// The SRC file.
113         /// The dest file.
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      /**////
139      /// 得到需要更新的文件清单
140      ///
141      /// Author:ZhangRongHua
142      /// Create DateTime: 2009-6-21 10:29
143      /// Update History:   
144      ///
145      ///
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;
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;
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;
256                string destFile = string.Concat(destPath, "\\", Path.GetFileName(srcFile));
257                try
258                {
259                  File.Copy(srcFile, destFile, true);
260                }
261                catch (System.IO.IOExceptionex)
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;
273                string tmpDestPath = String.Concat(destPath, "\\", Path.GetFileName(srcPath));
274                Directory.CreateDirectory(tmpDestPath);
275                CopyUpdateFiles(srcPath, tmpDestPath);
276            }
277      }
278
279
280
281      /**////
282      /// 更新完成后,要执行的动作(将下载的文件从临时目录复制到主目录,重启主程序)
283      ///
284      /// Author:ZhangRongHua
285      /// Create DateTime: 2009-6-21 12:25
286      /// Update History:   
287      ///
288      ///
289      /// The SRC path.
290      /// The dest path.
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;
327
328            lvUpdateList.Items.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.iyunv.com
页: [1]
查看完整版本: 实现客户端程序自动更新使用FTP