前些时间写的一个下载类,支持断点下载,多线程之类的,折腾了点时间才写出来

是用于在线更新的

写的不够好的地方希望大家提出来,我会继续改正

可能一下代码会比较长,看起来比较麻烦,我大概说一下用法,这个类我自己测试过是没有问题的

代码
1 Download load = new Download(dr["SourceUrl"].ToString());
2 load.ThreadCount = 5;
3 load.Filename = dr["FileName"].ToString();
4 load.DirectoryName = dr["Dest"].ToString();
5 load.Progress += new Download.ProgressEventHandler(load_Progress);
6 load.Finished += new Download.FinishedEventHandler(load_Finished);
7 load.Speed += new Download.SpeedHandler(load_Speed);
8 load.Start();

 

下面是全部代码

Download
  1 public class Download
  2     {
  3         public Download(string url)
  4         {
  5             this.Url = url;
  6             this.ThreadCount = 5;
  7         }
  8 
  9         #region 委托
 10 
 11         public delegate void ExceptionEventHandler(Download sender, Exception e);
 12         public delegate void ConnectedEventHandler(Download sender, string filename, string contentType);
 13         public delegate void ProgressEventHandler(Download sender);
 14         public delegate void FinishedEventHandler(Download sender);
 15         public delegate void SpeedHandler(Download sender);
 16 
 17         #endregion
 18 
 19         #region 成员
 20 
 21         private ExceptionEventHandler _exception;
 22         private ConnectedEventHandler _connected;
 23         private ProgressEventHandler _progress;
 24         private FinishedEventHandler _finished;
 25         private SpeedHandler _speed;
 26 
 27         private Thread thConnection;
 28         private Thread[] thDownloads;
 29         private Stream fileStream;
 30         private object lockFinishedLength = new object();
 31         private int postion = 2 * 2 * 64 * 1024;//块大小
 32 
 33         private Dictionary<stringint> SpeedDic = new Dictionary<stringint>();
 34 
 35         private string ConfigFile = "";
 36         #endregion
 37 
 38         #region 属性
 39 
 40         /// <summary>
 41         /// 下载线程数量
 42         /// </summary>
 43         public int ThreadCount { getset; }
 44 
 45         /// <summary>
 46         /// 下载资源位置
 47         /// </summary>
 48         public string Url { getset; }
 49 
 50         /// <summary>
 51         /// 资源保存路径
 52         /// </summary>
 53         public string Filename { getset; }
 54 
 55         /// <summary>
 56         /// 资源长度
 57         /// </summary>
 58         public long ContentLength { getprivate set; }
 59 
 60         /// <summary>
 61         /// 资源已下载长度
 62         /// </summary>
 63         public long FinishedLength { getprivate set; }
 64 
 65         /// <summary>
 66         /// 下载百分比
 67         /// </summary>
 68         public int FinishedRate { getprivate set; }
 69 
 70         /// <summary>
 71         /// 文件夹
 72         /// </summary>
 73         public string DirectoryName { getset; }
 74 
 75         /// <summary>
 76         /// 进度条
 77         /// </summary>
 78         public object ProgressBar { getset; }
 79 
 80         /// <summary>
 81         /// 控件
 82         /// </summary>
 83         public object Control { getset; }
 84 
 85         /// <summary>
 86         /// 速度
 87         /// </summary>
 88         public string SpeedStr { getprivate set; }
 89 
 90         #endregion
 91 
 92         #region 事件
 93 
 94         /// <summary>
 95         /// 当连接上资源后发生
 96         /// </summary>
 97         public event ConnectedEventHandler Connected
 98         {
 99             add
100             {
101                 this._connected += value;
102             }
103             remove
104             {
105                 this._connected -= value;
106             }
107         }
108 
109         /// <summary>
110         /// 当连下载进度变化后发生
111         /// </summary>
112         public event ProgressEventHandler Progress
113         {
114             add
115             {
116                 this._progress += value;
117             }
118             remove
119             {
120                 this._progress -= value;
121             }
122         }
123 
124         /// <summary>
125         /// 当下载完成后发生
126         /// </summary>
127         public event FinishedEventHandler Finished
128         {
129             add
130             {
131                 this._finished += value;
132             }
133             remove
134             {
135                 this._finished -= value;
136             }
137         }
138 
139         /// <summary>
140         /// 当连下载发生异常后发生
141         /// </summary>
142         public event ExceptionEventHandler Exception
143         {
144             add
145             {
146                 this._exception += value;
147             }
148             remove
149             {
150                 this._exception -= value;
151             }
152         }
153 
154         /// <summary>
155         /// 速度事件
156         /// </summary>
157         public event SpeedHandler Speed
158         {
159             add
160             {
161                 this._speed += value;
162             }
163             remove
164             {
165                 this._speed -= value;
166             }
167         }
168 
169         #endregion
170 
171         #region 响应
172 
173         protected void OnConnected(string filename, string contentType)
174         {
175             if (this._connected != null)
176             {
177                 this._connected.Invoke(this, filename, contentType);
178             }
179         }
180 
181         protected void OnProgress()
182         {
183             // 统计百分比
184             lock (this.lockFinishedLength)
185             {
186                 int rate = (int)(this.FinishedLength * 100 / this.ContentLength);
187                 if (rate != this.FinishedRate)
188                     this.FinishedRate = rate;
189                 else
190                     return;
191             }
192             // 进度事件处理
193             if (this._progress != null)
194             {
195                 lock (this._progress)
196                 {
197                     this._progress.Invoke(this);
198                 }
199             }
200         }
201 
202         protected void OnFinished()
203         {
204             bool isFinished = true;
205             lock (this.thDownloads)
206             {
207                 foreach (Thread thread in this.thDownloads)
208                 {
209                     if (thread != null)
210                         if (thread.ThreadState != ThreadState.Stopped && thread != Thread.CurrentThread)
211                         {
212                             isFinished = false;
213                             break;
214                         }
215                 }
216             }
217 
218             if (isFinished)
219             {
220                 this.fileStream.Close();
221 
222                 if (File.Exists(this.Filename))
223                 {
224                     File.Delete(this.Filename);
225                 }
226                 File.Move(this.Filename + ".tfg"this.Filename);
227 
228                 if (File.Exists(ConfigFile))
229                 {
230                     File.Delete(ConfigFile);
231                 }
232 
233                 if (this._finished != null)
234                 {
235                     this._finished.Invoke(this);
236                 }
237             }
238         }
239 
240         protected void OnException(Exception e)
241         {
242             this.Abort();
243 
244             if (this._exception != null)
245             {
246                 this._exception.Invoke(this, e);
247             }
248         }
249 
250         protected void OnSpeed()
251         {
252             int result = 0;
253             lock (SpeedDic)
254             {
255                 foreach (string key in SpeedDic.Keys)
256                 {
257                     result += SpeedDic[key];
258                 }
259             }
260             SpeedStr = result.ToString("f0"+ "KB/s";
261             if (this._speed != null)
262             {
263                 lock (this._speed)
264                 {
265                     this._speed.Invoke(this);
266                 }
267             }
268         }
269 
270         #endregion
271 
272         #region 方法
273 
274         /// <summary>
275         /// 开始下载
276         /// </summary>
277         public void Start()
278         {
279             if (thConnection == null)
280             {
281                 this.thConnection = new Thread(new ThreadStart(this.Connection));
282                 this.thConnection.Start();
283             }
284         }
285 
286         /// <summary>
287         /// 停止下载
288         /// </summary>
289         public void Stop()
290         {
291             // 停止连接
292             if (this.thConnection != null)
293             {
294                 this.thConnection.Abort();
295                 this.thConnection.Join();
296             }
297             // 停止下载
298             this.Abort();
299             // 释放资源
300             if (this.fileStream != null)
301             {
302                 this.fileStream.Dispose();
303             }
304         }
305 
306         /// <summary>
307         /// 终止下载线程
308         /// </summary>
309         private void Abort()
310         {
311             if (this.thDownloads != null)
312             {
313                 lock (this.thDownloads)
314                 {
315                     foreach (Thread thread in this.thDownloads)
316                     {
317                         if (thread != Thread.CurrentThread)
318                         {
319                             thread.Abort();
320                             thread.Join();
321                         }
322                     }
323                 }
324             }
325         }
326 
327         /// <summary>
328         /// 资源连接(读取资源长度,文件名称)
329         /// </summary>
330         private void Connection()
331         {
332             try
333             {
334                 // 请求
335                 HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(this.Url);
336                 request.Method = "Head";
337                 HttpWebResponse response = (HttpWebResponse)request.GetResponse();
338                 this.ContentLength = response.ContentLength;
339                 string filename = this.GetFilename(response.GetResponseHeader("Content-Disposition"));
340                 response.Close();
341 
342                 this.OnConnected(filename, response.ContentType);
343 
344                 if (this.ContentLength == 0)
345                 {
346                     this.OnFinished();
347                     return;
348                 }
349 
350                 // 下载
351                 if (this.ThreadCount < 1 || this.ThreadCount > 100)
352                 {
353                     throw new Exception("无效的线程数量");
354                 }
355 
356                 if (!Directory.Exists(DirectoryName))
357                 {
358                     Directory.CreateDirectory(DirectoryName);
359                 }
360 
361                 this.Filename = DirectoryName + "\\" + Filename;
362 
363                 ConfigFile = Filename + ".cfg";
364 
365                 #region [ 创建控制文件和空白文件 ]
366                 if (!File.Exists(ConfigFile))
367                 {
368                     WriteConfigFile();
369                     byte[] emptyByte = new byte[ContentLength];
370                     FileStream fs = new FileStream(this.Filename + ".tfg", FileMode.Create, FileAccess.Write);
371                     fs.Write(emptyByte, 0, emptyByte.Length);
372                     fs.Dispose();
373                     fs.Close();
374                 }
375                 #endregion
376 
377                 #region [ 下载断点 ]
378                 ArrayList MustDoan = new ArrayList();
379                 int complete = 0;
380                 string[] strBlocks = ReadConfigFile().Split(new char[2] { '\r''\n' });
381                 for (int j = 0; j < strBlocks.Length; j++)
382                 {
383                     if (strBlocks[j].Trim().Length != 0 && strBlocks[j].Substring(strBlocks[j].Length - 1== "0")
384                     {
385                         MustDoan.Add(strBlocks[j].Trim());
386                     }
387                     else if (strBlocks[j].Trim().Length != 0 && strBlocks[j].Substring(strBlocks[j].Length - 1== "1")
388                     {
389                         complete++;
390                     }
391                 }
392                 this.FinishedLength = complete * postion;
393                 #endregion
394 
395                 this.fileStream = new FileStream(this.Filename + ".tfg", FileMode.Open, FileAccess.Write);
396 
397                 this.thDownloads = new Thread[this.ThreadCount];
398                 int arrLen = MustDoan.Count;
399                 int modNum = arrLen / ThreadCount;
400                 int endNum = modNum + arrLen % ThreadCount;
401                 // int modNum =  (int)(this.ContentLength / this.thDownloads.Length);
402                 for (int i = 0; i < thDownloads.Length; i++)
403                 {
404                     int from = i * modNum;
405                     //int to = (i == thDownloads.Length - 1) ? (int)this.ContentLength : from + modNum;
406                     int to = from + (i == ThreadCount - 1 ? endNum : modNum);
407                     this.thDownloads[i] = new Thread(new ParameterizedThreadStart(this.DownloadBlock));
408                     this.thDownloads[i].Name = "T" + i;
409                     this.thDownloads[i].Start(new object[] { from, to, MustDoan });
410                 }
411             }
412             catch (Exception e)
413             {
414                 if (!(e is ThreadAbortException))
415                 {
416                     this.OnException(e);
417                 }
418             }
419         }
420 
421         /// <summary>
422         /// 下载数据
423         /// </summary>
424         private void DownloadBlock(object rang)
425         {
426             int from = Convert.ToInt32((rang as object[])[0]);
427             int to = Convert.ToInt32((rang as object[])[1]);
428             ArrayList MustDoan = (rang as object[])[2as ArrayList;
429 
430             HttpWebRequest hwRequest = null;
431             HttpWebResponse hwResponse = null;
432             Stream responseStream = null;
433             while (from < to)
434             {
435                 string[] strRecord = MustDoan[from].ToString().Split(',');
436                 int reStart = int.Parse(strRecord[0]);
437                 int reEnd = int.Parse(strRecord[1]);
438                 try
439                 {
440                     hwRequest = (HttpWebRequest)HttpWebRequest.Create(this.Url);
441                     hwRequest.AddRange(reStart, reStart + reEnd);
442                     hwResponse = (HttpWebResponse)hwRequest.GetResponse();
443                     responseStream = hwResponse.GetResponseStream();
444 
445                     byte[] buffer = new byte[1024 * 10];
446                     int size = 0, count = 0;
447                     TimeSpan tsBegin;
448                     DateTime dtBegin = DateTime.Now;
449                     int secondSize = size;
450                     do
451                     {
452                         DateTime dtEnd = DateTime.Now;
453                         tsBegin = dtEnd - dtBegin;
454                         if (tsBegin.TotalSeconds >= 1)
455                         {
456                             dtBegin = DateTime.Now;
457                             double totalSecond = tsBegin.TotalSeconds;
458                             double speed = secondSize / (totalSecond * 1024);
459                             SetSpeed(Thread.CurrentThread.Name, (int)speed);
460                             secondSize = 0;
461                         }
462 
463                         size = responseStream.Read(buffer, 0, buffer.Length);
464                         lock (this.lockFinishedLength)
465                         {
466                             this.FinishedLength += size;
467                         }
468 
469                         lock (this.fileStream)
470                         {
471                             this.fileStream.Seek(reStart + count, SeekOrigin.Begin);
472                             this.fileStream.Write(buffer, 0, size);
473                         }
474 
475                         UpdateConfigFile(MustDoan[from].ToString());
476 
477                         secondSize += size;
478                         reStart += size;
479                         this.OnProgress();
480                         this.OnSpeed();
481 
482                     } while (size > 0);
483                 }
484                 catch (Exception e)
485                 {
486                     if (!(e is ThreadAbortException))
487                     {
488                         this.OnException(e);
489                     }
490                 }
491                 finally
492                 {
493                     if (responseStream != null)
494                     {
495                         responseStream.Close();
496                     }
497                     if (hwResponse != null)
498                     {
499                         hwResponse.Close();
500                     }
501                 }
502                 from++;
503             }
504 
505             this.OnFinished();
506         }
507 
508         /// <summary>
509         /// 得到文件名称
510         /// </summary>
511         private string GetFilename(string contentDisposition)
512         {
513             string filename = "";
514             if (contentDisposition.IndexOf("filename="!= -1)
515             {
516                 filename = filename.Substring(filename.IndexOf("filename="+ 9);
517             }
518             else
519             {
520                 filename = this.Url.Substring(this.Url.LastIndexOf("/"+ 1);
521             }
522             return filename;
523         }
524 
525         /// <summary>
526         /// 创建控制文件
527         /// </summary>
528         private void WriteConfigFile()
529         {
530             StreamWriter sw = new StreamWriter(ConfigFile);
531             int p = 0;
532             int l = (int)this.ContentLength;
533             int m = postion;
534             while (l >= m)
535             {
536                 l -= m;
537                 if (l < m)
538                 {
539                     m += l;
540                 }
541                 sw.WriteLine(p.ToString() + "," + m.ToString() + "," + "0");
542                 p += m;
543             }
544             sw.Dispose();
545             sw.Close();
546         }
547 
548         /// <summary>
549         /// 读取控制文件
550         /// </summary>
551         /// <returns></returns>
552         public string ReadConfigFile()
553         {
554             string result = "";
555             using (StreamReader sr = new StreamReader(ConfigFile))
556             {
557                 result = sr.ReadToEnd().Trim();
558             }
559             return result;
560         }
561 
562         /// <summary>
563         /// 更新控制文件
564         /// </summary>
565         /// <param name="str"></param>
566         public void UpdateConfigFile(string str)
567         {
568             lock (ConfigFile)
569             {
570                 string s = null;
571                 using (StreamReader sr = new System.IO.StreamReader(ConfigFile))
572                 {
573                     s = sr.ReadToEnd().Trim();
574 
575                     string[] ss = str.Split(',');
576                     s = s.Replace(ss[0+ "," + ss[1+ ",0", ss[0+ "," + ss[1+ ",1");
577                 }
578                 using (StreamWriter sw = new StreamWriter(ConfigFile, false, Encoding.Default))
579                 {
580                     sw.WriteLine(s);
581                 }
582             }
583         }
584 
585         /// <summary>
586         /// SetSpeed
587         /// </summary>
588         /// <param name="threadName"></param>
589         /// <param name="speed"></param>
590         private void SetSpeed(string threadName, int speed)
591         {
592             lock (SpeedDic)
593             {
594                 if (SpeedDic.ContainsKey(threadName))
595                     SpeedDic[threadName] = speed;
596                 else
597                     SpeedDic.Add(threadName, speed);
598             }
599         }
600         #endregion
601     }
602 

 

 

posted on 2010-10-15 11:53  Yithcn  阅读(539)  评论(1编辑  收藏  举报