C# - DevExpress ProgressBarControl 을 활용한 FTP 서버 접속해서 다운 받는 AutoUpdate 프로그램.

2021. 2. 5. 14:12C#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Diagnostics;
 
namespace AutoUpdate
{
    public partial class Form1 : DevExpress.XtraEditors.XtraForm
    {
 
        #region Property
 
        private string id = "";
        private string pass = "";
        private string path = string.Format(@"ftp://{0}:{1}""""");//FTP IP, PORT 번호
        private string fullPath = string.Format(@"ftp://{0}:{1}/{2}/{3}/""""""""");//FTP IP,PORT,접속할 폴더
        private BackgroundWorker worker;
 
        #endregion
 
        public Form1()
        {
            InitializeComponent();
 
            #region BackgroundWorker 설정
 
            worker = new BackgroundWorker();
            worker.WorkerReportsProgress = true;
            worker.WorkerSupportsCancellation = true;
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
 
            #endregion
        }
 
 
        #region Load Methods
        private void Update_Load(object sender, EventArgs e)
        {
            worker.RunWorkerAsync();
        }
 
        #endregion
 
        #region FTP 접속 메서드
 
        /// <summary>
        /// FTP 접속 시 Response 객체 반환
        /// </summary>
        /// <param name="path">FTP 경로</param>
        /// <param name="method">FTP 접속 시 할 작업방법</param>
        /// <returns></returns>
 
        private FtpWebResponse FTPConnection(string path, string method)
        {
            FtpWebResponse response = null;
            try
            {
                FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create(path);
                ftpRequest.KeepAlive = false;
                ftpRequest.UseBinary = true;
                ftpRequest.Method = method;
                ftpRequest.Credentials = new NetworkCredential(id, pass);
 
                response = (FtpWebResponse)ftpRequest.GetResponse();
 
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString(), "ERROR"); ;
            }
            return response;
        }
        #endregion
 
        #region 이벤트
 
        #region 비동기로 실행할 작업
        private void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                #region 서버에 접속 가능한지 먼저 체크.
 
                FtpWebResponse ConResult = FTPConnection(path, WebRequestMethods.Ftp.ListDirectory);
 
                if (ConResult != null)
                {
 
                    #region 서버 접속 확인 후 접근할 폴더로 접근후 폴더,파일목록 저장
 
                    List<string> list = new List<string>();//폴더내의 목록 저장할 변수
 
                    using (FtpWebResponse response = FTPConnection(fullPath, WebRequestMethods.Ftp.ListDirectory))
                    {
                        using (Stream ftpStream = response.GetResponseStream())
                        {
                            using (StreamReader reader = new StreamReader(ftpStream))
                            {
                                while (true)//존재하는 모든 폴더와 파일목록 저장.
                                {
                                    string line = reader.ReadLine();
 
                                    if (string.IsNullOrWhiteSpace(line)) break;
 
                                    list.Add(line);
                                }
                            }
                        }
                    }
                    #endregion
 
 
                    #region 저장해온 폴더,파일 체크 후 다운로드
 
                    #region 전체 파일용량 구하기
 
                    float totalSize = 0;
 
                    foreach (string item in list)
                    {
                        if (item.Contains("."))
                        {
                            using (FtpWebResponse response = FTPConnection(fullPath + item, WebRequestMethods.Ftp.GetFileSize))
                            {
                                using (Stream ftpStream = response.GetResponseStream())
                                {
                                    totalSize += response.ContentLength;
                                }
                            }
                        }
                        else
                        {
                            #region 폴더일 경우 한번 더 아래로 진입 후 하위목록 가져오기
 
                            List<string> lowList = new List<string>();//폴더일 경우 한번더 들어가서 하위의 파일들을 저장하기 위한 변수
 
                            using (FtpWebResponse response = FTPConnection(fullPath + item, WebRequestMethods.Ftp.ListDirectory))
                            {
                                using (Stream ftpStream = response.GetResponseStream())
                                {
                                    using (StreamReader reader = new StreamReader(ftpStream))
                                    {
                                        while (true)//존재하는 모든 폴더와 파일목록 저장.
                                        {
                                            string line = reader.ReadLine();
 
                                            if (string.IsNullOrWhiteSpace(line)) break;
 
                                            lowList.Add(line);
                                        }
                                    }
                                }
                            }
 
                            #endregion
 
                            foreach (string lowItem in lowList)
                            {
                                using (FtpWebResponse response = FTPConnection(fullPath + item + "/" + lowItem, WebRequestMethods.Ftp.GetFileSize))
                                {
                                    using (Stream ftpStream = response.GetResponseStream())
                                    {
                                        totalSize += response.ContentLength;
                                    }
                                }
                            }
 
                        }
                    }
 
                    #endregion
 
                    foreach (string item in list)
                    {
 
                        if (item.Contains("."))//폴더가 아닌 파일일 경우 로컬로 다운로드.
                        {
 
                            #region 해당 파일의 사이즈와 수정시간 저장
                            float fileSize;//FTP서버의 해당 파일사이즈를 저장하기 위한 변수.
 
                            using (FtpWebResponse response = FTPConnection(fullPath + item, WebRequestMethods.Ftp.GetFileSize))
                            {
                                using (Stream ftpStream = response.GetResponseStream())
                                {
                                    fileSize = response.ContentLength;
                                }
                            }
 
                            DateTime ftpDt;//해당 파일의 마지막 수정시간을 저장하기 위한 변수.
 
                            using (FtpWebResponse response = FTPConnection(fullPath + item, WebRequestMethods.Ftp.GetDateTimestamp))
                            {
                                ftpDt = response.LastModified;
                            }
 
                            #endregion
 
                            //다운로드 시작.
                            using (FtpWebResponse response = FTPConnection(fullPath + item, WebRequestMethods.Ftp.DownloadFile))
                            {
 
                                DateTime localDt = DateTime.Parse("2000-01-01");//해당 파일이 없을 경우 DateTime입력. 새로운 파일을 다운로드하기위함.
 
                                FileInfo fi = new FileInfo(Application.StartupPath + "\\" + item);
 
                                if (fi.Exists)
                                {
                                    localDt = Directory.GetLastWriteTime(Application.StartupPath + "\\" + item);//LOCAL의 파일의 마지막 수정시간
                                }
 
                                if (0 < DateTime.Compare(ftpDt, localDt))//수정한 시간이 FTP서버파일이 더 최신이면 다운로드
                                {
                                    using (Stream ftpStream = response.GetResponseStream())
                                    {
                                        using (FileStream fs = new FileStream(Application.StartupPath + "\\" + item, FileMode.Create,
                                                                            FileAccess.Write, FileShare.None))
                                        {
                                            byte[] buffer = new byte[(int)fileSize];
                                            int readBytes = 0;
                                            while ((readBytes = ftpStream.Read(buffer, 0, buffer.Length)) > 0)
                                            {
                                                fs.Write(buffer, 0, readBytes);
                                                int progress = (int)((fileSize / totalSize) * 100);
                                                worker.ReportProgress(progress);
                                            }
 
                                            //ftpStream.CopyTo(fs);
                                        }
                                    }
 
                                }
                                else//수정시간이 같으면 다음 파일 검사.
                                {
                                    worker.ReportProgress(1);
                                    continue;
                                }
                            }
                        }
                        else//파일이 아닌 폴더일 경우 한번 더 접근 후 하위 파일들 얻고 로컬로 다운로드.
                        {
 
                            #region Local에서 폴더가 있는지 체크 후 폴더 생성
 
                            DirectoryInfo di = new DirectoryInfo(Application.StartupPath + "\\" + item);
                            if (!di.Exists)
                            {
                                di.Create();
                            }
 
                            #endregion
 
                            #region 폴더일 경우 한번 더 아래로 진입 후 하위목록 가져오기
                            List<string> lowList = new List<string>();//폴더일 경우 한번더 들어가서 하위의 파일들을 저장하기 위한 변수
 
                            using (FtpWebResponse response = FTPConnection(fullPath + item, WebRequestMethods.Ftp.ListDirectory))
                            {
                                using (Stream ftpStream = response.GetResponseStream())
                                {
                                    using (StreamReader reader = new StreamReader(ftpStream))
                                    {
                                        while (true)//존재하는 모든 폴더와 파일목록 저장.
                                        {
                                            string line = reader.ReadLine();
 
                                            if (string.IsNullOrWhiteSpace(line)) break;
 
                                            lowList.Add(line);
                                        }
                                            
                                    }
                                }
                            }
 
                            #endregion
 
 
                            foreach (string lowItem in lowList)
                            {
 
                                #region 해당 파일의 사이즈와 수정시간 저장
                                float fileSize;//FTP서버의 해당 파일사이즈를 저장하기 위한 변수.
 
                                using (FtpWebResponse response = FTPConnection(fullPath + item + "/" + lowItem, WebRequestMethods.Ftp.GetFileSize))
                                {
                                    using (Stream ftpStream = response.GetResponseStream())
                                    {
                                        fileSize = response.ContentLength;//FTP 서버의 파일의 용량
                                    }
                                }
 
                                DateTime ftpDt;//해당 파일의 마지막 수정시간을 저장하기 위한 변수.
 
                                using (FtpWebResponse response = FTPConnection(fullPath + item + "/" + lowItem, WebRequestMethods.Ftp.GetDateTimestamp))
                                {
                                    ftpDt = response.LastModified;//FTP 서버의 파일의 마지막 수정시간
                                }
 
                                #endregion
 
                                //다운로드 시작.
                                using (FtpWebResponse response = FTPConnection(fullPath + item + "/" + lowItem, WebRequestMethods.Ftp.DownloadFile))
                                {
                                    DateTime localDt = DateTime.Parse("2000-01-01");//해당 파일이 없을 경우 DateTime입력. 새로운 파일을 다운로드하기위함.
 
                                    FileInfo fi = new FileInfo(Application.StartupPath + "\\" + item + "\\" + lowItem);
 
                                    if (fi.Exists)
                                    {
                                        localDt = Directory.GetLastWriteTime(Application.StartupPath + "\\" + item + "\\" + lowItem);//LOCAL의 파일의 마지막 수정시간
                                    }
 
                                    if (0 < DateTime.Compare(ftpDt, localDt))//수정한 시간이 FTP서버파일이 더 최신이면 다운로드
                                    {
                                        using (Stream ftpStream = response.GetResponseStream())
                                        {
                                            using (FileStream fs = new FileStream(Application.StartupPath + "\\" + item + "\\" + lowItem, FileMode.Create,
                                                                                FileAccess.Write, FileShare.None))
                                            {
                                                byte[] buffer = new byte[(int)fileSize];
                                                int readBytes = 0;
                                                while ((readBytes = ftpStream.Read(buffer, 0, buffer.Length)) > 0)
                                                {
                                                    fs.Write(buffer, 0, readBytes);
                                                    int progress = (int)((fileSize / totalSize) * 100);
                                                    worker.ReportProgress(progress);
                                                }
 
                                                //ftpStream.CopyTo(fs);그냥 한번에 복사하는 방법.
                                            }
                                        }
 
                                    }
                                    else//수정시간이 같으면 다음 파일 검사.
                                    {
                                        worker.ReportProgress(1);
                                        continue;
                                    }
                                }
                            }
                        }
 
                    }
                    #endregion
 
                }
 
                worker.ReportProgress(100);
 
 
 
                #endregion
 
            }
            catch (Exception ex)
            {
 
                MessageBox.Show(ex.Message.ToString(), "ERROR",MessageBoxButtons.OK,MessageBoxIcon.Error);
 
                worker.CancelAsync();
                worker.Dispose();
 
                //자동업데이트 오류 발생 시 업데이트 하지 않고 오류메세지 출력 후 프로그램 실행.
 
                string mainPrg = Application.StartupPath + "";//Main 프로그램 명 입력.확장자포함
                Process main = new Process();
                main.StartInfo = new ProcessStartInfo(mainPrg);
                main.Start();
 
                Application.Exit();
                Environment.Exit(0);
 
 
            }
 
        }
 
        #endregion
 
        #region ProgressbarControl 상태 변화 이벤트
        private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBarControl1.Increment( e.ProgressPercentage);
        }
 
        #endregion
 
        #region 비동기 작업 완료시 발생 이벤트
        private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                MessageBox.Show("업데이트 완료""성공");
            }
 
            worker.CancelAsync();
            worker.Dispose();
 
            string mainPrg = Application.StartupPath + "";//Main 프로그램 명 입력.확장자포함
            Process main = new Process();
            main.StartInfo = new ProcessStartInfo(mainPrg);
            main.Start();
 
            Application.Exit();
            Environment.Exit(0);
 
 
        }
        #endregion
 
        #endregion
 
 
 
 
 
    }
}
 
cs

 

C#에서 DevExpress UI를 활용하여서 Auto Update 프로그램을 만들어 보았다.

그리고 진행률을 표시하기 위해서 ProgressbarControl 을 사용하여서 다운로드가 될때마다 부드럽게 진행률이 올라가게 만들었다.  최대한 주석을 달아 놓아서 그대로 복사 붙여넣기해서 FTP서버접속 IP,ID,Password 만 입력하고 실행되어야하는 프로그램명을 확장자 포함해서 적고 배포만 하면 된다. 배포를 해도 되고 Form 으로 하나 만들어서 Form close를 사용하여 다음 Form 을 열어줘도 무방하다.주의할점은 배포 후 실행될 프로그램 폴더안에 같이 넣어야 한다. 시간에 쫓겨서 2일만에 만든거 치고는 깔끔하게 작동이 잘되어서 뿌듯하다. 고수분들이 보기엔 허접하겠지만 혼자 뿌듯하니 만족한다. BackgroundWorker를 사용하여 메인 쓰레드는 UI 를 보여주며 진행률을 표시하고 별도의 Background쓰레드가 파일을 다운로드 받으며 진행상황을 메인쓰레드에 보고한다. 굳이 BarckgroundWorker를 사용하여 쓰레드를 나눠 작업을 하냐면 메인쓰레드가 파일을 다운받으면서 동시에 진행률을 올리는 UI작업이 안되기 때문에 쓰레드를 나눠 사용하는 것이다.  BackgroundWorker를 사용할때는 주의할점이 크로스 쓰레드 현상이 일어날수있다. 쉽게 말하면 파일 다운로드만 받고 진행률만 보고해야지 메인 쓰레드가 작업하고 있는 UI 를 건들려고 하면 접근을 못하게 된다. 혼자 하면서 공부도 많이 되었고 재밌는 작업이였던것 같다. 마지막에 업데이트 성공 메세지박스는 필요없을 시 삭제하여도 무방하다. DevExpresss를 사용하지 않고 그냥 Winform 을 사용하면 ProgressBar를 사용하면 되고 진행률을 업그레이드 할때는 progressBar1.value=e.ProgressPercentage 이렇게 Change이벤트에서 선언해주면 된다. 나와 같은 다른 초보분들이 헤메지 않게 도움이 잘 되었으면 좋겠다. 작업환경은 VS2017 Enterprise 이고 .NET 4.6.1이다.

 

'C#' 카테고리의 다른 글

Mini_Project  (0) 2020.11.02