(一) . 概述
最近做了个C/S文件下载工具, 支持多任务, 多线程和断点续传功能. 其中部分代码是从网上找来的, 自己改了
许多Bug, 并增加断点续传等功能.
由于公司具有代码所有权, 不能将源代码共享. 自己对比较Asp.net感兴趣, 业余时间自己做了个简单的, 基于Asp.net 2.0的, 功能虽然不是很强大, 但已经实现了多线程, 断点续传功能. 分享一下, 互相学习! 互相借鉴!
(二).运行效果
(三). 代码
1. 核心 DownLoadState.cs 文件代码
1 /// <summary>
2 /// Author: [ ChengKing(ZhengJian) ]
3 /// Blog: Http://blog.csdn.net/ChengKing
4 /// 注:从网上找了个优秀代码
5 /// 扩展如下功能:
6 /// 1. 解决一些线程相关的Bug;
7 /// 2.扩展用控制文件实现断点续传功能.
8 /// </summary>
9 namespace DownLoadComponent
10 {
11 /// <summary>
12 /// 多线程辅助类(Add by ChengKing)
13 /// </summary>
14 public class Task
15 {
16 string _FromFileName;
17 string _ToFileName;
18 int _ThreadNum;
19
20 public Task(string FromFileName, string ToFileName, int ThreadNum)
21 {
22 this._FromFileName = FromFileName;
23 this._ToFileName = ToFileName;
24 this._ThreadNum = ThreadNum;
25 }
26
27 public string FromFileName
28 {
29 get
30 {
31 return _FromFileName;
32 }
33 set
34 {
35 _FromFileName = value;
36 }
37 }
38 public string ToFileName
39 {
40 get
41 {
42 return _ToFileName;
43 }
44 set
45 {
46 _ToFileName = value;
47 }
48 }
49 public int ThreadNum
50 {
51 get
52 {
53 return _ThreadNum;
54 }
55 set
56 {
57 _ThreadNum = value;
58 }
59 }
60 }
61
62 /// <summary>
63 /// 记录下载的字节位置
64 /// </summary>
65 public class DownLoadState
66 {
67 private string _FileName;
68
69 private string _AttachmentName;
70 private int _Position;
71 private string _RequestURL;
72 private string _ResponseURL;
73 private int _Length;
74
75 private byte[] _Data;
76
77 public string FileName
78 {
79 get
80 {
81 return _FileName;
82 }
83 }
84
85 public int Position
86 {
87 get
88 {
89 return _Position;
90 }
91 }
92
93 public int Length
94 {
95 get
96 {
97 return _Length;
98 }
99 }
100
101
102 public string AttachmentName
103 {
104 get
105 {
106 return _AttachmentName;
107 }
108 }
109
110 public string RequestURL
111 {
112 get
113 {
114 return _RequestURL;
115 }
116 }
117
118 public string ResponseURL
119 {
120 get
121 {
122 return _ResponseURL;
123 }
124 }
125
126
127 public byte[] Data
128 {
129 get
130 {
131 return _Data;
132 }
133 }
134
135 internal DownLoadState(string RequestURL, string ResponseURL, string FileName, string AttachmentName, int Position, int Length, byte[] Data)
136 {
137 this._FileName = FileName;
138 this._RequestURL = RequestURL;
139 this._ResponseURL = ResponseURL;
140 this._AttachmentName = AttachmentName;
141 this._Position = Position;
142 this._Data = Data;
143 this._Length = Length;
144 }
145
146 internal DownLoadState(string RequestURL, string ResponseURL, string FileName, string AttachmentName, int Position, int Length, ThreadCallbackHandler tch)
147 {
148 this._RequestURL = RequestURL;
149 this._ResponseURL = ResponseURL;
150 this._FileName = FileName;
151 this._AttachmentName = AttachmentName;
152 this._Position = Position;
153 this._Length = Length;
154 this._ThreadCallback = tch;
155 }
156
157 internal DownLoadState(string RequestURL, string ResponseURL, string FileName, string AttachmentName, int Position, int Length)
158 {
159 this._RequestURL = RequestURL;
160 this._ResponseURL = ResponseURL;
161 this._FileName = FileName;
162 this._AttachmentName = AttachmentName;
163 this._Position = Position;
164 this._Length = Length;
165 }
166
167 private ThreadCallbackHandler _ThreadCallback;
168
169 //
170 internal void StartDownloadFileChunk()
171 {
172 if (this._ThreadCallback != null)
173 {
174 this._ThreadCallback(this._RequestURL, this._FileName, this._Position, this._Length);
175 }
176 }
177
178 }
179
180 //委托代理线程的所执行的方法签名一致
181 public delegate void ThreadCallbackHandler(string S, string s, int I, int i);
182
183 //异常处理动作
184 public enum ExceptionActions
185 {
186 Throw,
187 CancelAll,
188 Ignore,
189 Retry
190 }
191
192 /// <summary>
193 /// 包含 Exception 事件数据的类
194 /// </summary>
195 public class ExceptionEventArgs : System.EventArgs
196 {
197 private System.Exception _Exception;
198 private ExceptionActions _ExceptionAction;
199
200 private DownLoadState _DownloadState;
201
202 public DownLoadState DownloadState
203 {
204 get
205 {
206 return _DownloadState;
207 }
208 }
209
210 public Exception Exception
211 {
212 get
213 {
214 return _Exception;
215 }
216 }
217
218 public ExceptionActions ExceptionAction
219 {
220 get
221 {
222 return _ExceptionAction;
223 }
224 set
225 {
226 _ExceptionAction = value;
227 }
228 }
229
230 internal ExceptionEventArgs(System.Exception e, DownLoadState DownloadState)
231 {
232 this._Exception = e;
233 this._DownloadState = DownloadState;
234 }
235 }
236
237 /// <summary>
238 /// 包含 DownLoad 事件数据的类
239 /// </summary>
240 public class DownLoadEventArgs : System.EventArgs
241 {
242 private DownLoadState _DownloadState;
243
244 public DownLoadState DownloadState
245 {
246 get
247 {
248 return _DownloadState;
249 }
250 }
251
252 public DownLoadEventArgs(DownLoadState DownloadState)
253 {
254 this._DownloadState = DownloadState;
255 }
256
257 }
258
259 /// <summary>
260 /// 支持断点续传多线程下载的类
261 /// </summary>
262 public class HttpWebClient
263 {
264 private static object _SyncLockObject = new object();
265
266 public delegate void DataReceiveEventHandler(HttpWebClient Sender, DownLoadEventArgs e);
267
268 public event DataReceiveEventHandler DataReceive; //接收字节数据事件
269
270 public delegate void ExceptionEventHandler(HttpWebClient Sender, ExceptionEventArgs e);
271
272 public event ExceptionEventHandler ExceptionOccurrs; //发生异常事件
273
274 private int _FileLength; //下载文件的总大小
275
276 public static ArrayList threads;
277
278 public int FileLength
279 {
280 get
281 {
282 return _FileLength;
283 }
284 }
285
286 /// <summary>
287 /// 分块下载文件
288 /// </summary>
289 /// <param name="Address">URL 地址</param>
290 /// <param name="FileName">保存到本地的路径文件名</param>
291 /// <param name="ChunksCount">块数,线程数</param>
292 public void DownloadFile(string Address, string FileName, int ChunksCount)
293 {
294 int p = 0; // position
295 int s = 0; // chunk size
296 string a = null;
297 HttpWebRequest hwrq;
298 HttpWebResponse hwrp = null;
299 try
300 {
301
302 hwrq = (HttpWebRequest)WebRequest.Create(this.GetUri(Address));
303 //hwrq.Timeout = 20000000;
304 //if (hwrq.HaveResponse == false)
305 // return;
306 //hwrq.ProtocolVersion =HttpVersion.Version10;
307 //WebProxy wp = WebProxy.GetDefaultProxy();
308 //hwrq.Proxy = wp;
309 hwrq.Method = "GET";
310 try
311 {
312 hwrp = (HttpWebResponse)hwrq.GetResponse();
313 }
314 catch (Exception e)
315 {
316 throw new Exception(e.Message);
317 }
318
319 long L = hwrp.ContentLength;
320
321 //如果文件太小, 就不用分多线程, 用一个线程下载即可. (目前控制在800K)
322 //if (L < 800000)
323 //{
324 // ChunksCount = 1;
325 //}
326
327 hwrq.Credentials = this.m_credentials;
328
329 L = ((L == -1) || (L > 0x7fffffff)) ? ((long)0x7fffffff) : L; //Int32.MaxValue 该常数的值为 2,147,483,647; 即十六进制的 0x7FFFFFFF
330
331 int l = (int)L;
332
333 this._FileLength = l;
334
335 bool b = (hwrp.Headers["Accept-Ranges"] != null & hwrp.Headers["Accept-Ranges"] == "bytes");
336 a = hwrp.Headers["Content-Disposition"]; //attachment
337 if (a != null)
338 {
339 a = a.Substring(a.LastIndexOf("filename=") + 9);
340 }
341 else
342 {
343 a = FileName;
344 }
345
346 int ss = s;
347 if (b)
348 {
349 if (ExistControlFile(FileName)) //是否存在文件
350 {
351 string[] strBlocks = this.ReadInfFromControlFile(FileName).Split(new char[2] { '\r', '\n' });
352 for (int i = 0; i < strBlocks.Length; i++)
353 {
354 if (strBlocks[i].Trim().Length != 0 && strBlocks[i].Substring(strBlocks[i].Length - 1) == "0")
355 {
356 string[] strRecord = strBlocks[i].Split(',');
357 int p2 = int.Parse(strRecord[0]);
358 int s2 = int.Parse(strRecord[1]);
359 DownLoadState x = new DownLoadState(Address, hwrp.ResponseUri.AbsolutePath, FileName, a, p2, s2, new ThreadCallbackHandler(this.DownloadFileChunk));
360 Thread t = new Thread(new ThreadStart(x.StartDownloadFileChunk));
361 if (threads == null)
362 {
363 threads = new ArrayList();
364 }
365 threads.Add(t);
366 t.Start();
367 }
368
369
370 }
371
372 }
373 else
374 {
375 //建立控制文件
376 FileStream fs = File.Create(this.GetControlFileName(FileName));
377 fs.Close();
378
379 if (File.Exists(FileName))
380 {
381 FileInfo fi = new FileInfo(FileName);
382 if (fi.Length == L)
383 {
384 this.AddendInfToControlFile(FileName, 0, 0);
385 this.UpdateControlFile(FileName, 0, 0);
386 return;
387 }
388 }
389
390 s = l / ChunksCount;
391 if (s < 2 * 64 * 1024) //块大小至少为 128 K 字节
392 {
393 s = 2 * 64 * 1024;
394 }
395 ss = s;
396 int i = 0;
397 while (l >= s)
398 {
399 l -= s;
400 if (l < s)
401 {
402 s += l;
403 }
404 if (i++ > 0)
405 {
406 DownLoadState x = new DownLoadState(Address, hwrp.ResponseUri.AbsolutePath, FileName, a, p, s, new ThreadCallbackHandler(this.DownloadFileChunk));
407
408 AddendInfToControlFile(FileName, p, s);
409 Thread t = new Thread(new ThreadStart(x.StartDownloadFileChunk));
410 if (threads == null)
411 {
412 threads = new ArrayList();
413 }
414 threads.Add(t);
415 t.Start();
416
417 }
418 p += s;
419 }
420 s = ss;
421
422 AddendInfToControlFile(FileName, 0, s);
423 DownLoadState x1 = new DownLoadState(Address, hwrp.ResponseUri.AbsolutePath, FileName, a, 0, s, new ThreadCallbackHandler(this.DownloadFileChunk));
424 Thread t2 = new Thread(new ThreadStart(x1.StartDownloadFileChunk));
425 if (threads == null)
426 {
427 threads = new ArrayList();
428 }
429 threads.Add(t2);
430 t2.Start();
431 }
432 }
433 //如果服务器不支持断点续传(Accept-Range), 则使用单线程下载
434 else
435 {
436 AddendInfToControlFile(FileName, 0, l);
437 DownLoadState x = new DownLoadState(Address, hwrp.ResponseUri.AbsolutePath, FileName, a, 0, l, new ThreadCallbackHandler(this.DownloadFileChunk));
438 Thread t = new Thread(new ThreadStart(x.StartDownloadFileChunk));
439 if (threads == null)
440 {
441 threads = new ArrayList();
442 }
443 threads.Add(t);
444 t.Start();
445 }
446 }
447 catch (Exception e)
448 {
449 //if (blnReturn == true)
450 //{
451 // return;
452 //}
453
454 ExceptionActions ea = ExceptionActions.Throw;
455 if (ea == ExceptionActions.Throw)
456 {
457 if (!(e is WebException) && !(e is SecurityException))
458 {
459 throw new WebException("net_webclient", e);
460 }
461 throw;
462 }
463
464
465 //if (this.ExceptionOccurrs != null)
466 //{
467 // DownLoadState x = new DownLoadState(Address, hwrp.ResponseUri.AbsolutePath, FileName, a, p, s);
468
469 // ExceptionEventArgs eea = new ExceptionEventArgs(e, x);
470 // ExceptionOccurrs(this, eea);
471 // ea = eea.ExceptionAction;
472 //}
473
474 }
475
476 }
477
478 #region 操作控制文件(By King Zheng)
479
480 /// <summary>
481 /// 插入文件块信息到控制文件(Add by ChengKing)
482 /// </summary>
483 /// <param name="FileName"></param>
484 /// <param name="Position"></param>
485 /// <param name="Length"></param>
486 private void AddendInfToControlFile(string FileName, int Position, int Length)
487 {
488
489
490 try
491 {
492 lock (_SyncLockObject)
493 {
494 string strControlFile = GetControlFileName(FileName);
495
496
497 //if (File.Exists(strControlFile) == false)
498 //{
499 // return;
500 //}
501
502 using (StreamWriter sw = new StreamWriter(strControlFile, true, Encoding.Default))
503 {
504 //sw.NewLine = "$";
505 sw.WriteLine(Position.ToString() + "," + Length.ToString() + "," + "0");
506 }
507 //using (System.IO.FileStream sw = new System.IO.FileStream(strControlFile, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite, System.IO.FileShare.ReadWrite))
508 //{
509 // //sw.Position = e.DownloadState.Position;
510 // sw.Write(Position.ToString() + "," + Length.ToString() + "," + "0");
511 // sw.Close();
512 //}
513
514
515
516 }
517 }
518 catch (Exception e)
519 {
520 throw new Exception("写控制文件出错!" + e.Message);
521 }
522
523 }
524
525 /// <summary>
526 /// 更新控制文件(Add by ChengKing)
527 /// </summary>
528 /// <param name="FileName"></param>
529 /// <param name="Position"></param>
530 /// <param name="Length"></param>
531 private void UpdateControlFile(string FileName, int Position, int Length)
532 {
533 try
534 {
535 lock (_SyncLockObject)
536 {
537 string strControlFile = GetControlFileName(FileName);
538
539
540 //if (File.Exists(strControlFile) == false)
541 //{
542 // return;
543 //}
544
545 string s = null;
546 using (StreamReader sr = new System.IO.StreamReader(strControlFile))
547 {
548 s = sr.ReadToEnd();
549 s = s.Replace(Position.ToString() + "," + Length.ToString() + "," + "0", Position.ToString() + "," + Length.ToString() + "," + "1");
550 }
551 using (StreamWriter sw = new StreamWriter(strControlFile, false, Encoding.Default))
552 {
553 sw.WriteLine(s);
554 }
555 }
556 }
557 catch (Exception e)
558 {
559 throw new Exception("更新控制文件出错!" + e.Message);
560 }
561
562 }
563
564 /// <summary>
565 /// 读取所有信息从控制文件(Add by ChengKing)
566 /// </summary>
567 /// <param name="FileName"></param>
568 /// <returns></returns>
569 private string ReadInfFromControlFile(string FileName)
570 {
571 try
572 {
573 lock (_SyncLockObject)
574 {
575 string strControlFile = GetControlFileName(FileName);
576
577 string s = null;
578 using (StreamReader sr = new System.IO.StreamReader(strControlFile))
579 {
580 s = sr.ReadToEnd();
581
582 }
583 return s;
584 }
585 }
586 catch (Exception e)
587 {
588 throw new Exception("读控制文件出错!" + e.Message);
589 }
590 }
591
592 /// <summary>
593 /// 根据目标文件名得到控制文件名(Add by ChengKing)
594 /// </summary>
595 /// <param name="FileName"></param>
596 /// <returns></returns>
597 public string GetControlFileName(string FileName)
598 {
599 string strPath = Path.GetDirectoryName(FileName);
600
601 //string strFileNameWithoutExtension = Path.GetFileNameWithoutExtension(FileName);
602 string strFileNameWithoutExtension = Path.GetFileName(FileName);
603 string strControlFile = Path.Combine(strPath, strFileNameWithoutExtension + "_Control.txt");
604 return strControlFile;
605 }
606
607 /// <summary>
608 /// 判断控制文件是否存在
609 /// </summary>
610 /// <param name="FileName"></param>
611 /// <returns></returns>
612 private bool ExistControlFile(string FileName)
613 {
614 string strControlFile = GetControlFileName(FileName);
615 if (File.Exists(strControlFile))
616 {
617 return true;
618 }
619 return false;
620 }
621
622 /// <summary>
623 /// 判断控制文件是否完成
624 /// </summary>
625 /// <param name="strControlFile"></param>
626 /// <returns></returns>
627 public bool JudgeControlFileIfFinished(string strControlFile)
628 {
629 try
630 {
631 string s = null;
632 lock (_SyncLockObject)
633 {
634 using (StreamReader sr = new System.IO.StreamReader(strControlFile))
635 {
636 s = sr.ReadToEnd();
637 }
638 }
639 if (s + String.Empty == String.Empty)
640 {
641 return false;
642 }
643 string[] strBlocks = s.Split(new char[2] { '\r', '\n' });
644 for (int i = 0; i < strBlocks.Length; i++)
645 {
646 if (strBlocks[i].Trim().Length != 0 && strBlocks[i].Substring(strBlocks[i].Length - 1) == "0")
647 {
648 return false;
649 }
650 }
651 return true;
652
653 }
654 catch (Exception e)
655 {
656 throw new Exception("判断控制文件是否完成时, 读取文件出错!" + e.Message);
657 }
658 }
659
660 /// <summary>
661 /// 删除控制文件(Add by ChengKing)
662 /// </summary>
663 /// <param name="strControlFile"></param>
664 /// <returns></returns>
665 public bool DeleteControlFile(string strControlFile)
666 {
667 try
668 {
669 lock (_SyncLockObject)
670 {
671 if (File.Exists(strControlFile))
672 {
673 File.Delete(strControlFile);
674 }
675 }
676 return true;
677 }
678 catch (Exception e)
679 {
680 throw new Exception("删除控制文件出错!" + e.Message);
681 }
682 }
683
684 #endregion
685
686 /// <summary>
687 /// 下载一个文件块,利用该方法可自行实现多线程断点续传
688 /// </summary>
689 /// <param name="Address">URL 地址</param>
690 /// <param name="FileName">保存到本地的路径文件名</param>
691 /// <param name="Length">块大小</param>
692 public void DownloadFileChunk(string Address, string FileName, int FromPosition, int Length)
693 {
694 HttpWebResponse hwrp = null;
695 string a = null;
696 try
697 {
698 //this._FileName = FileName;
699 HttpWebRequest hwrq = (HttpWebRequest)WebRequest.Create(this.GetUri(Address));
700 //hwrq.Credentials = this.m_credentials;
701
702 hwrq.AddRange(FromPosition);
703
704 hwrp = (HttpWebResponse)hwrq.GetResponse();
705
706 //hwrp.Headers.Add("Content-Range", FromPosition.ToString()); //Test
707
708 a = hwrp.Headers["Content-Disposition"]; //attachment
709 if (a != null)
710 {
711 a = a.Substring(a.LastIndexOf("filename=") + 9);
712 }
713 else
714 {
715 a = FileName;
716 }
717
718 byte[] buffer = this.ResponseAsBytes(Address, hwrp, Length, FileName);
719 // lock (_SyncLockObject)
720 // {
721 // this._Bytes += buffer.Length;
722 // }
723 }
724 catch (Exception e)
725 {
726 ExceptionActions ea = ExceptionActions.Throw;
727 if (this.ExceptionOccurrs != null)
728 {
729 DownLoadState x = new DownLoadState(Address, hwrp.ResponseUri.AbsolutePath, FileName, a, FromPosition, Length);
730 ExceptionEventArgs eea = new ExceptionEventArgs(e, x);
731 ExceptionOccurrs(this, eea);
732 ea = eea.ExceptionAction;
733 }
734
735 if (ea == ExceptionActions.Throw)
736 {
737 if (!(e is WebException) && !(e is SecurityException))
738 {
739 throw new WebException("net_webclient", e);
740 }
741 throw;
742 }
743 }
744 }
745
746 internal byte[] ResponseAsBytes(string RequestURL, WebResponse Response, long Length, string FileName)
747 {
748 string a = null; //AttachmentName
749 int P = 0; //整个文件的位置指针
750 int num2 = 0;
751 int num3 = 0;
752 int intFrom = 0;
753 try
754 {
755 a = Response.Headers["Content-Disposition"]; //attachment
756 if (a != null)
757 {
758 a = a.Substring(a.LastIndexOf("filename=") + 9);
759 }
760
761 long num1 = Length; //Response.ContentLength;
762 bool flag1 = false;
763 if (num1 == -1)
764 {
765 flag1 = true;
766 num1 = 0x10000; //64k
767 }
768 byte[] buffer1 = new byte[(long)num1];
769
770
771 int p = 0; //本块的位置指针
772
773 string s = Response.Headers["Content-Range"];
774 //string s = hwrq.Headers["Range"];
775
776 if (s != null)
777 {
778 s = s.Replace("bytes ", "");
779 s = s.Substring(0, s.IndexOf("-"));
780 P = Convert.ToInt32(s);
781 intFrom = P;
782
783 }
784
785 //int num3 = 0;
786
787 Stream S = Response.GetResponseStream();
788
789 int count = 0;
790
791 int bufferSize = 65535; //允许读取的最大字节
792
793 int times;
794 do
795 {
796 times = 0;
797
798 //num2 = S.Read(buffer1, num3, ((int)num1) - num3);
799
800 //限制最大读取字节
801 if (bufferSize < ((int)num1) - num3)
802 {
803 num2 = S.Read(buffer1, num3, bufferSize);
804 }
805 else
806 {
807 num2 = S.Read(buffer1, num3, ((int)num1) - num3);
808 }
809
810 //网络短时间的不稳定
811 if (num2 == 0)
812 {
813 Thread.Sleep(50);
814 times++;
815
816 if (times > 100)
817 {
818 throw new Exception("网络传输层错误");
819 }
820
821 }
822
823 num3 += num2;
824 if (flag1 && (num3 == num1))
825 {
826 num1 += 0x10000;
827 byte[] buffer2 = new byte[(int)num1];
828 Buffer.BlockCopy(buffer1, 0, buffer2, 0, num3);
829 buffer1 = buffer2;
830 }
831
832 // lock (_SyncLockObject)
833 // {
834 // this._bytes += num2;
835 // }
836 if (num2 > 0)
837 {
838 if (this.DataReceive != null)
839 {
840 byte[] buffer = new byte[num2];
841 Buffer.BlockCopy(buffer1, p, buffer, 0, buffer.Length);
842 DownLoadState dls = new DownLoadState(RequestURL, Response.ResponseUri.AbsolutePath, FileName, a, P, num2, buffer);
843 DownLoadEventArgs dlea = new DownLoadEventArgs(dls);
844
845 //触发事件
846 this.OnDataReceive(dlea);
847 //System.Threading.Thread.Sleep(100);
848
849 }
850 p += num2; //本块的位置指针
851 P += num2; //整个文件的位置指针
852 }
853 else
854 {
855 break;
856 }
857
858 }
859 while (num2 != 0);
860
861 count++;
862
863 int c = count;
864
865 S.Close();
866 S = null;
867 if (flag1)
868 {
869 byte[] buffer3 = new byte[num3];
870 Buffer.BlockCopy(buffer1, 0, buffer3, 0, num3);
871 buffer1 = buffer3;
872 }
873
874 UpdateControlFile(FileName, intFrom, (int)Length);
875
876 return buffer1;
877 }
878 catch (Exception e)
879 {
880 ExceptionActions ea = ExceptionActions.Throw;
881 if (this.ExceptionOccurrs != null)
882 {
883 Thread.Sleep(100);
884 //DownLoadState x = new DownLoadState(RequestURL, Response.ResponseUri.AbsolutePath, FileName, a, P, num2);
885 //DownLoadState x = new DownLoadState(RequestURL, Response.ResponseUri.AbsolutePath, FileName, a, P, (int)(Length - num3));
886 DownLoadState x = new DownLoadState(RequestURL, Response.ResponseUri.AbsolutePath, FileName, a, P, (int)Length);
887
888 ExceptionEventArgs eea = new ExceptionEventArgs(e, x);
889 ExceptionOccurrs(this, eea);
890 ea = eea.ExceptionAction;
891 }
892
893 if (ea == ExceptionActions.Throw)
894 {
895 if (!(e is WebException) && !(e is SecurityException))
896 {
897 throw new WebException("net_webclient", e);
898 }
899 throw;
900 }
901 return null;
902 }
903 }
904
905 private void OnDataReceive(DownLoadEventArgs e)
906 {
907 //触发数据到达事件
908 DataReceive(this, e);
909 }
910
911 public byte[] UploadFile(string address, string fileName)
912 {
913 return this.UploadFile(address, "POST", fileName, "file");
914 }
915
916 public string UploadFileEx(string address, string method, string fileName, string fieldName)
917 {
918 return Encoding.ASCII.GetString(UploadFile(address, method, fileName, fieldName));
919 }
920
921 public byte[] UploadFile(string address, string method, string fileName, string fieldName)
922 {
923 byte[] buffer4;
924 FileStream stream1 = null;
925 try
926 {
927 fileName = Path.GetFullPath(fileName);
928 string text1 = "---------------------" + DateTime.Now.Ticks.ToString("x");
929
930 string text2 = "application/octet-stream";
931
932 stream1 = new FileStream(fileName, FileMode.Open, FileAccess.Read);
933 WebRequest request1 = WebRequest.Create(this.GetUri(address));
934 request1.Credentials = this.m_credentials;
935 request1.ContentType = "multipart/form-data; boundary=" + text1;
936
937 request1.Method = method;
938 string[] textArray1 = new string[7] { "--", text1, "\r\nContent-Disposition: form-data; name=\"" + fieldName + "\"; filename=\"", Path.GetFileName(fileName), "\"\r\nContent-Type: ", text2, "\r\n\r\n" };
939 string text3 = string.Concat(textArray1);
940 byte[] buffer1 = Encoding.UTF8.GetBytes(text3);
941 byte[] buffer2 = Encoding.ASCII.GetBytes("\r\n--" + text1 + "\r\n");
942 long num1 = 0x7fffffffffffffff;
943 try
944 {
945 num1 = stream1.Length;
946 request1.ContentLength = (num1 + buffer1.Length) + buffer2.Length;
947 }
948 catch
949 {
950 }
951 byte[] buffer3 = new byte[Math.Min(0x2000, (int)num1)];
952 using (Stream stream2 = request1.GetRequestStream())
953 {
954 int num2;
955 stream2.Write(buffer1, 0, buffer1.Length);
956 do
957 {
958 num2 = stream1.Read(buffer3, 0, buffer3.Length);
959 if (num2 != 0)
960 {
961 stream2.Write(buffer3, 0, num2);
962 }
963 }
964 while (num2 != 0);
965 stream2.Write(buffer2, 0, buffer2.Length);
966 }
967 stream1.Close();
968 stream1 = null;
969 WebResponse response1 = request1.GetResponse();
970
971 buffer4 = this.ResponseAsBytes(response1);
972 }
973 catch (Exception exception1)
974 {
975 if (stream1 != null)
976 {
977 stream1.Close();
978 stream1 = null;
979 }
980 if (!(exception1 is WebException) && !(exception1 is SecurityException))
981 {
982 //throw new WebException(SR.GetString("net_webclient"), exception1);
983 throw new WebException("net_webclient", exception1);
984 }
985 throw;
986 }
987 return buffer4;
988 }
989
990 private byte[] ResponseAsBytes(WebResponse response)
991 {
992 int num2;
993 long num1 = response.ContentLength;
994 bool flag1 = false;
995 if (num1 == -1)
996 {
997 flag1 = true;
998 num1 = 0x10000;
999 }
1000 byte[] buffer1 = new byte[(int)num1];
1001 Stream stream1 = response.GetResponseStream();
1002 int num3 = 0;
1003 do
1004 {
1005 num2 = stream1.Read(buffer1, num3, ((int)num1) - num3);
1006 num3 += num2;
1007 if (flag1 && (num3 == num1))
1008 {
1009 num1 += 0x10000;
1010 byte[] buffer2 = new byte[(int)num1];
1011 Buffer.BlockCopy(buffer1, 0, buffer2, 0, num3);
1012 buffer1 = buffer2;
1013 }
1014 }
1015 while (num2 != 0);
1016 stream1.Close();
1017 if (flag1)
1018 {
1019 byte[] buffer3 = new byte[num3];
1020 Buffer.BlockCopy(buffer1, 0, buffer3, 0, num3);
1021 buffer1 = buffer3;
1022 }
1023 return buffer1;
1024 }
1025
1026 private NameValueCollection m_requestParameters;
1027 private Uri m_baseAddress;
1028 private ICredentials m_credentials = CredentialCache.DefaultCredentials;
1029
1030 public ICredentials Credentials
1031 {
1032 get
1033 {
1034 return this.m_credentials;
1035 }
1036 set
1037 {
1038 this.m_credentials = value;
1039 }
1040 }
1041
1042 public NameValueCollection QueryString
1043 {
1044 get
1045 {
1046 if (this.m_requestParameters == null)
1047 {
1048 this.m_requestParameters = new NameValueCollection();
1049 }
1050 return this.m_requestParameters;
1051 }
1052 set
1053 {
1054 this.m_requestParameters = value;
1055 }
1056 }
1057
1058 public string BaseAddress
1059 {
1060 get
1061 {
1062 if (this.m_baseAddress != null)
1063 {
1064 return this.m_baseAddress.ToString();
1065 }
1066 return string.Empty;
1067 }
1068 set
1069 {
1070 if ((value == null) || (value.Length == 0))
1071 {
1072 this.m_baseAddress = null;
1073 }
1074 else
1075 {
1076 try
1077 {
1078 this.m_baseAddress = new Uri(value);
1079 }
1080 catch (Exception exception1)
1081 {
1082 throw new ArgumentException("value", exception1);
1083 }
1084 }
1085 }
1086 }
1087
1088 public Uri GetUri(string path)
1089 {
1090 Uri uri1;
1091 try
1092 {
1093 if (this.m_baseAddress != null)
1094 {
1095 uri1 = new Uri(this.m_baseAddress, path);
1096 }
1097 else
1098 {
1099 uri1 = new Uri(path);
1100 }
1101 if (this.m_requestParameters == null)
1102 {
1103 return uri1;
1104 }
1105 StringBuilder builder1 = new StringBuilder();
1106 string text1 = string.Empty;
1107 for (int num1 = 0; num1 < this.m_requestParameters.Count; num1++)
1108 {
1109 builder1.Append(text1 + this.m_requestParameters.AllKeys[num1] + "=" + this.m_requestParameters[num1]);
1110 text1 = "&";
1111 }
1112 UriBuilder builder2 = new UriBuilder(uri1);
1113 builder2.Query = builder1.ToString();
1114 uri1 = builder2.Uri;
1115 }
1116 catch (UriFormatException)
1117 {
1118 uri1 = new Uri(Path.GetFullPath(path));
1119 }
1120 return uri1;
1121 }
1122
1123 }
1124
1125 }
1126
1127
2 /// Author: [ ChengKing(ZhengJian) ]
3 /// Blog: Http://blog.csdn.net/ChengKing
4 /// 注:从网上找了个优秀代码
5 /// 扩展如下功能:
6 /// 1. 解决一些线程相关的Bug;
7 /// 2.扩展用控制文件实现断点续传功能.
8 /// </summary>
9 namespace DownLoadComponent
10 {
11 /// <summary>
12 /// 多线程辅助类(Add by ChengKing)
13 /// </summary>
14 public class Task
15 {
16 string _FromFileName;
17 string _ToFileName;
18 int _ThreadNum;
19
20 public Task(string FromFileName, string ToFileName, int ThreadNum)
21 {
22 this._FromFileName = FromFileName;
23 this._ToFileName = ToFileName;
24 this._ThreadNum = ThreadNum;
25 }
26
27 public string FromFileName
28 {
29 get
30 {
31 return _FromFileName;
32 }
33 set
34 {
35 _FromFileName = value;
36 }
37 }
38 public string ToFileName
39 {
40 get
41 {
42 return _ToFileName;
43 }
44 set
45 {
46 _ToFileName = value;
47 }
48 }
49 public int ThreadNum
50 {
51 get
52 {
53 return _ThreadNum;
54 }
55 set
56 {
57 _ThreadNum = value;
58 }
59 }
60 }
61
62 /// <summary>
63 /// 记录下载的字节位置
64 /// </summary>
65 public class DownLoadState
66 {
67 private string _FileName;
68
69 private string _AttachmentName;
70 private int _Position;
71 private string _RequestURL;
72 private string _ResponseURL;
73 private int _Length;
74
75 private byte[] _Data;
76
77 public string FileName
78 {
79 get
80 {
81 return _FileName;
82 }
83 }
84
85 public int Position
86 {
87 get
88 {
89 return _Position;
90 }
91 }
92
93 public int Length
94 {
95 get
96 {
97 return _Length;
98 }
99 }
100
101
102 public string AttachmentName
103 {
104 get
105 {
106 return _AttachmentName;
107 }
108 }
109
110 public string RequestURL
111 {
112 get
113 {
114 return _RequestURL;
115 }
116 }
117
118 public string ResponseURL
119 {
120 get
121 {
122 return _ResponseURL;
123 }
124 }
125
126
127 public byte[] Data
128 {
129 get
130 {
131 return _Data;
132 }
133 }
134
135 internal DownLoadState(string RequestURL, string ResponseURL, string FileName, string AttachmentName, int Position, int Length, byte[] Data)
136 {
137 this._FileName = FileName;
138 this._RequestURL = RequestURL;
139 this._ResponseURL = ResponseURL;
140 this._AttachmentName = AttachmentName;
141 this._Position = Position;
142 this._Data = Data;
143 this._Length = Length;
144 }
145
146 internal DownLoadState(string RequestURL, string ResponseURL, string FileName, string AttachmentName, int Position, int Length, ThreadCallbackHandler tch)
147 {
148 this._RequestURL = RequestURL;
149 this._ResponseURL = ResponseURL;
150 this._FileName = FileName;
151 this._AttachmentName = AttachmentName;
152 this._Position = Position;
153 this._Length = Length;
154 this._ThreadCallback = tch;
155 }
156
157 internal DownLoadState(string RequestURL, string ResponseURL, string FileName, string AttachmentName, int Position, int Length)
158 {
159 this._RequestURL = RequestURL;
160 this._ResponseURL = ResponseURL;
161 this._FileName = FileName;
162 this._AttachmentName = AttachmentName;
163 this._Position = Position;
164 this._Length = Length;
165 }
166
167 private ThreadCallbackHandler _ThreadCallback;
168
169 //
170 internal void StartDownloadFileChunk()
171 {
172 if (this._ThreadCallback != null)
173 {
174 this._ThreadCallback(this._RequestURL, this._FileName, this._Position, this._Length);
175 }
176 }
177
178 }
179
180 //委托代理线程的所执行的方法签名一致
181 public delegate void ThreadCallbackHandler(string S, string s, int I, int i);
182
183 //异常处理动作
184 public enum ExceptionActions
185 {
186 Throw,
187 CancelAll,
188 Ignore,
189 Retry
190 }
191
192 /// <summary>
193 /// 包含 Exception 事件数据的类
194 /// </summary>
195 public class ExceptionEventArgs : System.EventArgs
196 {
197 private System.Exception _Exception;
198 private ExceptionActions _ExceptionAction;
199
200 private DownLoadState _DownloadState;
201
202 public DownLoadState DownloadState
203 {
204 get
205 {
206 return _DownloadState;
207 }
208 }
209
210 public Exception Exception
211 {
212 get
213 {
214 return _Exception;
215 }
216 }
217
218 public ExceptionActions ExceptionAction
219 {
220 get
221 {
222 return _ExceptionAction;
223 }
224 set
225 {
226 _ExceptionAction = value;
227 }
228 }
229
230 internal ExceptionEventArgs(System.Exception e, DownLoadState DownloadState)
231 {
232 this._Exception = e;
233 this._DownloadState = DownloadState;
234 }
235 }
236
237 /// <summary>
238 /// 包含 DownLoad 事件数据的类
239 /// </summary>
240 public class DownLoadEventArgs : System.EventArgs
241 {
242 private DownLoadState _DownloadState;
243
244 public DownLoadState DownloadState
245 {
246 get
247 {
248 return _DownloadState;
249 }
250 }
251
252 public DownLoadEventArgs(DownLoadState DownloadState)
253 {
254 this._DownloadState = DownloadState;
255 }
256
257 }
258
259 /// <summary>
260 /// 支持断点续传多线程下载的类
261 /// </summary>
262 public class HttpWebClient
263 {
264 private static object _SyncLockObject = new object();
265
266 public delegate void DataReceiveEventHandler(HttpWebClient Sender, DownLoadEventArgs e);
267
268 public event DataReceiveEventHandler DataReceive; //接收字节数据事件
269
270 public delegate void ExceptionEventHandler(HttpWebClient Sender, ExceptionEventArgs e);
271
272 public event ExceptionEventHandler ExceptionOccurrs; //发生异常事件
273
274 private int _FileLength; //下载文件的总大小
275
276 public static ArrayList threads;
277
278 public int FileLength
279 {
280 get
281 {
282 return _FileLength;
283 }
284 }
285
286 /// <summary>
287 /// 分块下载文件
288 /// </summary>
289 /// <param name="Address">URL 地址</param>
290 /// <param name="FileName">保存到本地的路径文件名</param>
291 /// <param name="ChunksCount">块数,线程数</param>
292 public void DownloadFile(string Address, string FileName, int ChunksCount)
293 {
294 int p = 0; // position
295 int s = 0; // chunk size
296 string a = null;
297 HttpWebRequest hwrq;
298 HttpWebResponse hwrp = null;
299 try
300 {
301
302 hwrq = (HttpWebRequest)WebRequest.Create(this.GetUri(Address));
303 //hwrq.Timeout = 20000000;
304 //if (hwrq.HaveResponse == false)
305 // return;
306 //hwrq.ProtocolVersion =HttpVersion.Version10;
307 //WebProxy wp = WebProxy.GetDefaultProxy();
308 //hwrq.Proxy = wp;
309 hwrq.Method = "GET";
310 try
311 {
312 hwrp = (HttpWebResponse)hwrq.GetResponse();
313 }
314 catch (Exception e)
315 {
316 throw new Exception(e.Message);
317 }
318
319 long L = hwrp.ContentLength;
320
321 //如果文件太小, 就不用分多线程, 用一个线程下载即可. (目前控制在800K)
322 //if (L < 800000)
323 //{
324 // ChunksCount = 1;
325 //}
326
327 hwrq.Credentials = this.m_credentials;
328
329 L = ((L == -1) || (L > 0x7fffffff)) ? ((long)0x7fffffff) : L; //Int32.MaxValue 该常数的值为 2,147,483,647; 即十六进制的 0x7FFFFFFF
330
331 int l = (int)L;
332
333 this._FileLength = l;
334
335 bool b = (hwrp.Headers["Accept-Ranges"] != null & hwrp.Headers["Accept-Ranges"] == "bytes");
336 a = hwrp.Headers["Content-Disposition"]; //attachment
337 if (a != null)
338 {
339 a = a.Substring(a.LastIndexOf("filename=") + 9);
340 }
341 else
342 {
343 a = FileName;
344 }
345
346 int ss = s;
347 if (b)
348 {
349 if (ExistControlFile(FileName)) //是否存在文件
350 {
351 string[] strBlocks = this.ReadInfFromControlFile(FileName).Split(new char[2] { '\r', '\n' });
352 for (int i = 0; i < strBlocks.Length; i++)
353 {
354 if (strBlocks[i].Trim().Length != 0 && strBlocks[i].Substring(strBlocks[i].Length - 1) == "0")
355 {
356 string[] strRecord = strBlocks[i].Split(',');
357 int p2 = int.Parse(strRecord[0]);
358 int s2 = int.Parse(strRecord[1]);
359 DownLoadState x = new DownLoadState(Address, hwrp.ResponseUri.AbsolutePath, FileName, a, p2, s2, new ThreadCallbackHandler(this.DownloadFileChunk));
360 Thread t = new Thread(new ThreadStart(x.StartDownloadFileChunk));
361 if (threads == null)
362 {
363 threads = new ArrayList();
364 }
365 threads.Add(t);
366 t.Start();
367 }
368
369
370 }
371
372 }
373 else
374 {
375 //建立控制文件
376 FileStream fs = File.Create(this.GetControlFileName(FileName));
377 fs.Close();
378
379 if (File.Exists(FileName))
380 {
381 FileInfo fi = new FileInfo(FileName);
382 if (fi.Length == L)
383 {
384 this.AddendInfToControlFile(FileName, 0, 0);
385 this.UpdateControlFile(FileName, 0, 0);
386 return;
387 }
388 }
389
390 s = l / ChunksCount;
391 if (s < 2 * 64 * 1024) //块大小至少为 128 K 字节
392 {
393 s = 2 * 64 * 1024;
394 }
395 ss = s;
396 int i = 0;
397 while (l >= s)
398 {
399 l -= s;
400 if (l < s)
401 {
402 s += l;
403 }
404 if (i++ > 0)
405 {
406 DownLoadState x = new DownLoadState(Address, hwrp.ResponseUri.AbsolutePath, FileName, a, p, s, new ThreadCallbackHandler(this.DownloadFileChunk));
407
408 AddendInfToControlFile(FileName, p, s);
409 Thread t = new Thread(new ThreadStart(x.StartDownloadFileChunk));
410 if (threads == null)
411 {
412 threads = new ArrayList();
413 }
414 threads.Add(t);
415 t.Start();
416
417 }
418 p += s;
419 }
420 s = ss;
421
422 AddendInfToControlFile(FileName, 0, s);
423 DownLoadState x1 = new DownLoadState(Address, hwrp.ResponseUri.AbsolutePath, FileName, a, 0, s, new ThreadCallbackHandler(this.DownloadFileChunk));
424 Thread t2 = new Thread(new ThreadStart(x1.StartDownloadFileChunk));
425 if (threads == null)
426 {
427 threads = new ArrayList();
428 }
429 threads.Add(t2);
430 t2.Start();
431 }
432 }
433 //如果服务器不支持断点续传(Accept-Range), 则使用单线程下载
434 else
435 {
436 AddendInfToControlFile(FileName, 0, l);
437 DownLoadState x = new DownLoadState(Address, hwrp.ResponseUri.AbsolutePath, FileName, a, 0, l, new ThreadCallbackHandler(this.DownloadFileChunk));
438 Thread t = new Thread(new ThreadStart(x.StartDownloadFileChunk));
439 if (threads == null)
440 {
441 threads = new ArrayList();
442 }
443 threads.Add(t);
444 t.Start();
445 }
446 }
447 catch (Exception e)
448 {
449 //if (blnReturn == true)
450 //{
451 // return;
452 //}
453
454 ExceptionActions ea = ExceptionActions.Throw;
455 if (ea == ExceptionActions.Throw)
456 {
457 if (!(e is WebException) && !(e is SecurityException))
458 {
459 throw new WebException("net_webclient", e);
460 }
461 throw;
462 }
463
464
465 //if (this.ExceptionOccurrs != null)
466 //{
467 // DownLoadState x = new DownLoadState(Address, hwrp.ResponseUri.AbsolutePath, FileName, a, p, s);
468
469 // ExceptionEventArgs eea = new ExceptionEventArgs(e, x);
470 // ExceptionOccurrs(this, eea);
471 // ea = eea.ExceptionAction;
472 //}
473
474 }
475
476 }
477
478 #region 操作控制文件(By King Zheng)
479
480 /// <summary>
481 /// 插入文件块信息到控制文件(Add by ChengKing)
482 /// </summary>
483 /// <param name="FileName"></param>
484 /// <param name="Position"></param>
485 /// <param name="Length"></param>
486 private void AddendInfToControlFile(string FileName, int Position, int Length)
487 {
488
489
490 try
491 {
492 lock (_SyncLockObject)
493 {
494 string strControlFile = GetControlFileName(FileName);
495
496
497 //if (File.Exists(strControlFile) == false)
498 //{
499 // return;
500 //}
501
502 using (StreamWriter sw = new StreamWriter(strControlFile, true, Encoding.Default))
503 {
504 //sw.NewLine = "$";
505 sw.WriteLine(Position.ToString() + "," + Length.ToString() + "," + "0");
506 }
507 //using (System.IO.FileStream sw = new System.IO.FileStream(strControlFile, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite, System.IO.FileShare.ReadWrite))
508 //{
509 // //sw.Position = e.DownloadState.Position;
510 // sw.Write(Position.ToString() + "," + Length.ToString() + "," + "0");
511 // sw.Close();
512 //}
513
514
515
516 }
517 }
518 catch (Exception e)
519 {
520 throw new Exception("写控制文件出错!" + e.Message);
521 }
522
523 }
524
525 /// <summary>
526 /// 更新控制文件(Add by ChengKing)
527 /// </summary>
528 /// <param name="FileName"></param>
529 /// <param name="Position"></param>
530 /// <param name="Length"></param>
531 private void UpdateControlFile(string FileName, int Position, int Length)
532 {
533 try
534 {
535 lock (_SyncLockObject)
536 {
537 string strControlFile = GetControlFileName(FileName);
538
539
540 //if (File.Exists(strControlFile) == false)
541 //{
542 // return;
543 //}
544
545 string s = null;
546 using (StreamReader sr = new System.IO.StreamReader(strControlFile))
547 {
548 s = sr.ReadToEnd();
549 s = s.Replace(Position.ToString() + "," + Length.ToString() + "," + "0", Position.ToString() + "," + Length.ToString() + "," + "1");
550 }
551 using (StreamWriter sw = new StreamWriter(strControlFile, false, Encoding.Default))
552 {
553 sw.WriteLine(s);
554 }
555 }
556 }
557 catch (Exception e)
558 {
559 throw new Exception("更新控制文件出错!" + e.Message);
560 }
561
562 }
563
564 /// <summary>
565 /// 读取所有信息从控制文件(Add by ChengKing)
566 /// </summary>
567 /// <param name="FileName"></param>
568 /// <returns></returns>
569 private string ReadInfFromControlFile(string FileName)
570 {
571 try
572 {
573 lock (_SyncLockObject)
574 {
575 string strControlFile = GetControlFileName(FileName);
576
577 string s = null;
578 using (StreamReader sr = new System.IO.StreamReader(strControlFile))
579 {
580 s = sr.ReadToEnd();
581
582 }
583 return s;
584 }
585 }
586 catch (Exception e)
587 {
588 throw new Exception("读控制文件出错!" + e.Message);
589 }
590 }
591
592 /// <summary>
593 /// 根据目标文件名得到控制文件名(Add by ChengKing)
594 /// </summary>
595 /// <param name="FileName"></param>
596 /// <returns></returns>
597 public string GetControlFileName(string FileName)
598 {
599 string strPath = Path.GetDirectoryName(FileName);
600
601 //string strFileNameWithoutExtension = Path.GetFileNameWithoutExtension(FileName);
602 string strFileNameWithoutExtension = Path.GetFileName(FileName);
603 string strControlFile = Path.Combine(strPath, strFileNameWithoutExtension + "_Control.txt");
604 return strControlFile;
605 }
606
607 /// <summary>
608 /// 判断控制文件是否存在
609 /// </summary>
610 /// <param name="FileName"></param>
611 /// <returns></returns>
612 private bool ExistControlFile(string FileName)
613 {
614 string strControlFile = GetControlFileName(FileName);
615 if (File.Exists(strControlFile))
616 {
617 return true;
618 }
619 return false;
620 }
621
622 /// <summary>
623 /// 判断控制文件是否完成
624 /// </summary>
625 /// <param name="strControlFile"></param>
626 /// <returns></returns>
627 public bool JudgeControlFileIfFinished(string strControlFile)
628 {
629 try
630 {
631 string s = null;
632 lock (_SyncLockObject)
633 {
634 using (StreamReader sr = new System.IO.StreamReader(strControlFile))
635 {
636 s = sr.ReadToEnd();
637 }
638 }
639 if (s + String.Empty == String.Empty)
640 {
641 return false;
642 }
643 string[] strBlocks = s.Split(new char[2] { '\r', '\n' });
644 for (int i = 0; i < strBlocks.Length; i++)
645 {
646 if (strBlocks[i].Trim().Length != 0 && strBlocks[i].Substring(strBlocks[i].Length - 1) == "0")
647 {
648 return false;
649 }
650 }
651 return true;
652
653 }
654 catch (Exception e)
655 {
656 throw new Exception("判断控制文件是否完成时, 读取文件出错!" + e.Message);
657 }
658 }
659
660 /// <summary>
661 /// 删除控制文件(Add by ChengKing)
662 /// </summary>
663 /// <param name="strControlFile"></param>
664 /// <returns></returns>
665 public bool DeleteControlFile(string strControlFile)
666 {
667 try
668 {
669 lock (_SyncLockObject)
670 {
671 if (File.Exists(strControlFile))
672 {
673 File.Delete(strControlFile);
674 }
675 }
676 return true;
677 }
678 catch (Exception e)
679 {
680 throw new Exception("删除控制文件出错!" + e.Message);
681 }
682 }
683
684 #endregion
685
686 /// <summary>
687 /// 下载一个文件块,利用该方法可自行实现多线程断点续传
688 /// </summary>
689 /// <param name="Address">URL 地址</param>
690 /// <param name="FileName">保存到本地的路径文件名</param>
691 /// <param name="Length">块大小</param>
692 public void DownloadFileChunk(string Address, string FileName, int FromPosition, int Length)
693 {
694 HttpWebResponse hwrp = null;
695 string a = null;
696 try
697 {
698 //this._FileName = FileName;
699 HttpWebRequest hwrq = (HttpWebRequest)WebRequest.Create(this.GetUri(Address));
700 //hwrq.Credentials = this.m_credentials;
701
702 hwrq.AddRange(FromPosition);
703
704 hwrp = (HttpWebResponse)hwrq.GetResponse();
705
706 //hwrp.Headers.Add("Content-Range", FromPosition.ToString()); //Test
707
708 a = hwrp.Headers["Content-Disposition"]; //attachment
709 if (a != null)
710 {
711 a = a.Substring(a.LastIndexOf("filename=") + 9);
712 }
713 else
714 {
715 a = FileName;
716 }
717
718 byte[] buffer = this.ResponseAsBytes(Address, hwrp, Length, FileName);
719 // lock (_SyncLockObject)
720 // {
721 // this._Bytes += buffer.Length;
722 // }
723 }
724 catch (Exception e)
725 {
726 ExceptionActions ea = ExceptionActions.Throw;
727 if (this.ExceptionOccurrs != null)
728 {
729 DownLoadState x = new DownLoadState(Address, hwrp.ResponseUri.AbsolutePath, FileName, a, FromPosition, Length);
730 ExceptionEventArgs eea = new ExceptionEventArgs(e, x);
731 ExceptionOccurrs(this, eea);
732 ea = eea.ExceptionAction;
733 }
734
735 if (ea == ExceptionActions.Throw)
736 {
737 if (!(e is WebException) && !(e is SecurityException))
738 {
739 throw new WebException("net_webclient", e);
740 }
741 throw;
742 }
743 }
744 }
745
746 internal byte[] ResponseAsBytes(string RequestURL, WebResponse Response, long Length, string FileName)
747 {
748 string a = null; //AttachmentName
749 int P = 0; //整个文件的位置指针
750 int num2 = 0;
751 int num3 = 0;
752 int intFrom = 0;
753 try
754 {
755 a = Response.Headers["Content-Disposition"]; //attachment
756 if (a != null)
757 {
758 a = a.Substring(a.LastIndexOf("filename=") + 9);
759 }
760
761 long num1 = Length; //Response.ContentLength;
762 bool flag1 = false;
763 if (num1 == -1)
764 {
765 flag1 = true;
766 num1 = 0x10000; //64k
767 }
768 byte[] buffer1 = new byte[(long)num1];
769
770
771 int p = 0; //本块的位置指针
772
773 string s = Response.Headers["Content-Range"];
774 //string s = hwrq.Headers["Range"];
775
776 if (s != null)
777 {
778 s = s.Replace("bytes ", "");
779 s = s.Substring(0, s.IndexOf("-"));
780 P = Convert.ToInt32(s);
781 intFrom = P;
782
783 }
784
785 //int num3 = 0;
786
787 Stream S = Response.GetResponseStream();
788
789 int count = 0;
790
791 int bufferSize = 65535; //允许读取的最大字节
792
793 int times;
794 do
795 {
796 times = 0;
797
798 //num2 = S.Read(buffer1, num3, ((int)num1) - num3);
799
800 //限制最大读取字节
801 if (bufferSize < ((int)num1) - num3)
802 {
803 num2 = S.Read(buffer1, num3, bufferSize);
804 }
805 else
806 {
807 num2 = S.Read(buffer1, num3, ((int)num1) - num3);
808 }
809
810 //网络短时间的不稳定
811 if (num2 == 0)
812 {
813 Thread.Sleep(50);
814 times++;
815
816 if (times > 100)
817 {
818 throw new Exception("网络传输层错误");
819 }
820
821 }
822
823 num3 += num2;
824 if (flag1 && (num3 == num1))
825 {
826 num1 += 0x10000;
827 byte[] buffer2 = new byte[(int)num1];
828 Buffer.BlockCopy(buffer1, 0, buffer2, 0, num3);
829 buffer1 = buffer2;
830 }
831
832 // lock (_SyncLockObject)
833 // {
834 // this._bytes += num2;
835 // }
836 if (num2 > 0)
837 {
838 if (this.DataReceive != null)
839 {
840 byte[] buffer = new byte[num2];
841 Buffer.BlockCopy(buffer1, p, buffer, 0, buffer.Length);
842 DownLoadState dls = new DownLoadState(RequestURL, Response.ResponseUri.AbsolutePath, FileName, a, P, num2, buffer);
843 DownLoadEventArgs dlea = new DownLoadEventArgs(dls);
844
845 //触发事件
846 this.OnDataReceive(dlea);
847 //System.Threading.Thread.Sleep(100);
848
849 }
850 p += num2; //本块的位置指针
851 P += num2; //整个文件的位置指针
852 }
853 else
854 {
855 break;
856 }
857
858 }
859 while (num2 != 0);
860
861 count++;
862
863 int c = count;
864
865 S.Close();
866 S = null;
867 if (flag1)
868 {
869 byte[] buffer3 = new byte[num3];
870 Buffer.BlockCopy(buffer1, 0, buffer3, 0, num3);
871 buffer1 = buffer3;
872 }
873
874 UpdateControlFile(FileName, intFrom, (int)Length);
875
876 return buffer1;
877 }
878 catch (Exception e)
879 {
880 ExceptionActions ea = ExceptionActions.Throw;
881 if (this.ExceptionOccurrs != null)
882 {
883 Thread.Sleep(100);
884 //DownLoadState x = new DownLoadState(RequestURL, Response.ResponseUri.AbsolutePath, FileName, a, P, num2);
885 //DownLoadState x = new DownLoadState(RequestURL, Response.ResponseUri.AbsolutePath, FileName, a, P, (int)(Length - num3));
886 DownLoadState x = new DownLoadState(RequestURL, Response.ResponseUri.AbsolutePath, FileName, a, P, (int)Length);
887
888 ExceptionEventArgs eea = new ExceptionEventArgs(e, x);
889 ExceptionOccurrs(this, eea);
890 ea = eea.ExceptionAction;
891 }
892
893 if (ea == ExceptionActions.Throw)
894 {
895 if (!(e is WebException) && !(e is SecurityException))
896 {
897 throw new WebException("net_webclient", e);
898 }
899 throw;
900 }
901 return null;
902 }
903 }
904
905 private void OnDataReceive(DownLoadEventArgs e)
906 {
907 //触发数据到达事件
908 DataReceive(this, e);
909 }
910
911 public byte[] UploadFile(string address, string fileName)
912 {
913 return this.UploadFile(address, "POST", fileName, "file");
914 }
915
916 public string UploadFileEx(string address, string method, string fileName, string fieldName)
917 {
918 return Encoding.ASCII.GetString(UploadFile(address, method, fileName, fieldName));
919 }
920
921 public byte[] UploadFile(string address, string method, string fileName, string fieldName)
922 {
923 byte[] buffer4;
924 FileStream stream1 = null;
925 try
926 {
927 fileName = Path.GetFullPath(fileName);
928 string text1 = "---------------------" + DateTime.Now.Ticks.ToString("x");
929
930 string text2 = "application/octet-stream";
931
932 stream1 = new FileStream(fileName, FileMode.Open, FileAccess.Read);
933 WebRequest request1 = WebRequest.Create(this.GetUri(address));
934 request1.Credentials = this.m_credentials;
935 request1.ContentType = "multipart/form-data; boundary=" + text1;
936
937 request1.Method = method;
938 string[] textArray1 = new string[7] { "--", text1, "\r\nContent-Disposition: form-data; name=\"" + fieldName + "\"; filename=\"", Path.GetFileName(fileName), "\"\r\nContent-Type: ", text2, "\r\n\r\n" };
939 string text3 = string.Concat(textArray1);
940 byte[] buffer1 = Encoding.UTF8.GetBytes(text3);
941 byte[] buffer2 = Encoding.ASCII.GetBytes("\r\n--" + text1 + "\r\n");
942 long num1 = 0x7fffffffffffffff;
943 try
944 {
945 num1 = stream1.Length;
946 request1.ContentLength = (num1 + buffer1.Length) + buffer2.Length;
947 }
948 catch
949 {
950 }
951 byte[] buffer3 = new byte[Math.Min(0x2000, (int)num1)];
952 using (Stream stream2 = request1.GetRequestStream())
953 {
954 int num2;
955 stream2.Write(buffer1, 0, buffer1.Length);
956 do
957 {
958 num2 = stream1.Read(buffer3, 0, buffer3.Length);
959 if (num2 != 0)
960 {
961 stream2.Write(buffer3, 0, num2);
962 }
963 }
964 while (num2 != 0);
965 stream2.Write(buffer2, 0, buffer2.Length);
966 }
967 stream1.Close();
968 stream1 = null;
969 WebResponse response1 = request1.GetResponse();
970
971 buffer4 = this.ResponseAsBytes(response1);
972 }
973 catch (Exception exception1)
974 {
975 if (stream1 != null)
976 {
977 stream1.Close();
978 stream1 = null;
979 }
980 if (!(exception1 is WebException) && !(exception1 is SecurityException))
981 {
982 //throw new WebException(SR.GetString("net_webclient"), exception1);
983 throw new WebException("net_webclient", exception1);
984 }
985 throw;
986 }
987 return buffer4;
988 }
989
990 private byte[] ResponseAsBytes(WebResponse response)
991 {
992 int num2;
993 long num1 = response.ContentLength;
994 bool flag1 = false;
995 if (num1 == -1)
996 {
997 flag1 = true;
998 num1 = 0x10000;
999 }
1000 byte[] buffer1 = new byte[(int)num1];
1001 Stream stream1 = response.GetResponseStream();
1002 int num3 = 0;
1003 do
1004 {
1005 num2 = stream1.Read(buffer1, num3, ((int)num1) - num3);
1006 num3 += num2;
1007 if (flag1 && (num3 == num1))
1008 {
1009 num1 += 0x10000;
1010 byte[] buffer2 = new byte[(int)num1];
1011 Buffer.BlockCopy(buffer1, 0, buffer2, 0, num3);
1012 buffer1 = buffer2;
1013 }
1014 }
1015 while (num2 != 0);
1016 stream1.Close();
1017 if (flag1)
1018 {
1019 byte[] buffer3 = new byte[num3];
1020 Buffer.BlockCopy(buffer1, 0, buffer3, 0, num3);
1021 buffer1 = buffer3;
1022 }
1023 return buffer1;
1024 }
1025
1026 private NameValueCollection m_requestParameters;
1027 private Uri m_baseAddress;
1028 private ICredentials m_credentials = CredentialCache.DefaultCredentials;
1029
1030 public ICredentials Credentials
1031 {
1032 get
1033 {
1034 return this.m_credentials;
1035 }
1036 set
1037 {
1038 this.m_credentials = value;
1039 }
1040 }
1041
1042 public NameValueCollection QueryString
1043 {
1044 get
1045 {
1046 if (this.m_requestParameters == null)
1047 {
1048 this.m_requestParameters = new NameValueCollection();
1049 }
1050 return this.m_requestParameters;
1051 }
1052 set
1053 {
1054 this.m_requestParameters = value;
1055 }
1056 }
1057
1058 public string BaseAddress
1059 {
1060 get
1061 {
1062 if (this.m_baseAddress != null)
1063 {
1064 return this.m_baseAddress.ToString();
1065 }
1066 return string.Empty;
1067 }
1068 set
1069 {
1070 if ((value == null) || (value.Length == 0))
1071 {
1072 this.m_baseAddress = null;
1073 }
1074 else
1075 {
1076 try
1077 {
1078 this.m_baseAddress = new Uri(value);
1079 }
1080 catch (Exception exception1)
1081 {
1082 throw new ArgumentException("value", exception1);
1083 }
1084 }
1085 }
1086 }
1087
1088 public Uri GetUri(string path)
1089 {
1090 Uri uri1;
1091 try
1092 {
1093 if (this.m_baseAddress != null)
1094 {
1095 uri1 = new Uri(this.m_baseAddress, path);
1096 }
1097 else
1098 {
1099 uri1 = new Uri(path);
1100 }
1101 if (this.m_requestParameters == null)
1102 {
1103 return uri1;
1104 }
1105 StringBuilder builder1 = new StringBuilder();
1106 string text1 = string.Empty;
1107 for (int num1 = 0; num1 < this.m_requestParameters.Count; num1++)
1108 {
1109 builder1.Append(text1 + this.m_requestParameters.AllKeys[num1] + "=" + this.m_requestParameters[num1]);
1110 text1 = "&";
1111 }
1112 UriBuilder builder2 = new UriBuilder(uri1);
1113 builder2.Query = builder1.ToString();
1114 uri1 = builder2.Uri;
1115 }
1116 catch (UriFormatException)
1117 {
1118 uri1 = new Uri(Path.GetFullPath(path));
1119 }
1120 return uri1;
1121 }
1122
1123 }
1124
1125 }
1126
1127
2.页面 Default.aspx 文件 代码
1 <html xmlns="http://www.w3.org/1999/xhtml" >
2 <head runat="server">
3 <script language="javascript">
4 mainLoop = function()
5 {
6 var objPath = document.getElementById("TextBox2");
7 var blnValue = _Default.CheckControlFiles(objPath.value);
8 //a.value = a.value + blnValue.value;
9 if( blnValue.value == true)
10 {
11 var returnvalue=setTimeout('mainLoop()', 1000);
12 }
13 else
14 {
15 var objStatus = document.getElementById("Label1");
16 objStatus.innerText = "状态: 下载完成!";
17
18 var btOK = document.getElementById("btOK");
19 btOK.disabled = "";
20
21 var btCancel = document.getElementById("btCancel");
22 btCancel.disabled = "disabled";
23
24 }
25 }
26
27
28 </script>
29
30 </head>
31 <body>
32 <form id="frmTest" runat="server" >
33 <table bgcolor="#ffcc66"><tr><td style="height: 259px">
34 <br />
35 <strong><span style="color: #000099">
36 下载组件:
37 <br />
38 1. 支持多线程: 多个线程某时刻下载同一个文件的不同块.<br />
39 2. 断点续传: 如果下载了一个文件的某些块(一半), 则下次<br />
40 下载时只需下载未完成的块;
41 文件块的下载状<br />
42 态用控制文件记录.
43 块下载完成的先后顺序不<br />
44 一定是连续的.<br />
45 </span></strong>
46 <br />
47 <table style="width: 379px">
48 <tr>
49 <td colspan="1" style="width: 87px">
50 Source</td>
51 <td colspan="2" style="width: 326px">
52 <asp:TextBox ID="TextBox1" runat="server" Width="391px">http://www.</asp:TextBox></td>
53 </tr>
54 <tr>
55 <td colspan="1" style="width: 87px">
56 Location</td>
57 <td colspan="2" style="width: 326px">
58 <asp:TextBox ID="TextBox2" runat="server" Width="391px">D:\Documents and Settings\zhengjian\桌面\TestDownLoads\</asp:TextBox></td>
59 </tr>
60 <tr>
61 <td colspan="1" style="width: 87px">
62 Threads</td>
63 <td colspan="2" style="width: 326px">
64 <asp:TextBox ID="TextBox3" runat="server" Width="390px">10</asp:TextBox></td>
65 </tr>
66 </table>
67 <br />
68 <asp:Button ID="btOK" runat="server" Text="下载" Height="42px" Width="108px" OnClick="btOK_Click" />
69 <asp:Button ID="btCancel" runat="server" OnClick="btCancel_Click" Text="取消/暂停" Height="42px" Width="108px" Enabled="False" /><br />
70 <br />
71 <asp:Label ID="Label1" runat="server" Height="32px" Text="状态: 未开始下载" Width="227px" Font-Bold="True" ForeColor="#8080FF"></asp:Label><br />
72 </td></tr></table>
73 <script language=javascript>
74 mainLoop();
75 </script>
76 </form>
77 </body>
78 </html>
2 <head runat="server">
3 <script language="javascript">
4 mainLoop = function()
5 {
6 var objPath = document.getElementById("TextBox2");
7 var blnValue = _Default.CheckControlFiles(objPath.value);
8 //a.value = a.value + blnValue.value;
9 if( blnValue.value == true)
10 {
11 var returnvalue=setTimeout('mainLoop()', 1000);
12 }
13 else
14 {
15 var objStatus = document.getElementById("Label1");
16 objStatus.innerText = "状态: 下载完成!";
17
18 var btOK = document.getElementById("btOK");
19 btOK.disabled = "";
20
21 var btCancel = document.getElementById("btCancel");
22 btCancel.disabled = "disabled";
23
24 }
25 }
26
27
28 </script>
29
30 </head>
31 <body>
32 <form id="frmTest" runat="server" >
33 <table bgcolor="#ffcc66"><tr><td style="height: 259px">
34 <br />
35 <strong><span style="color: #000099">
36 下载组件:
37 <br />
38 1. 支持多线程: 多个线程某时刻下载同一个文件的不同块.<br />
39 2. 断点续传: 如果下载了一个文件的某些块(一半), 则下次<br />
40 下载时只需下载未完成的块;
41 文件块的下载状<br />
42 态用控制文件记录.
43 块下载完成的先后顺序不<br />
44 一定是连续的.<br />
45 </span></strong>
46 <br />
47 <table style="width: 379px">
48 <tr>
49 <td colspan="1" style="width: 87px">
50 Source</td>
51 <td colspan="2" style="width: 326px">
52 <asp:TextBox ID="TextBox1" runat="server" Width="391px">http://www.</asp:TextBox></td>
53 </tr>
54 <tr>
55 <td colspan="1" style="width: 87px">
56 Location</td>
57 <td colspan="2" style="width: 326px">
58 <asp:TextBox ID="TextBox2" runat="server" Width="391px">D:\Documents and Settings\zhengjian\桌面\TestDownLoads\</asp:TextBox></td>
59 </tr>
60 <tr>
61 <td colspan="1" style="width: 87px">
62 Threads</td>
63 <td colspan="2" style="width: 326px">
64 <asp:TextBox ID="TextBox3" runat="server" Width="390px">10</asp:TextBox></td>
65 </tr>
66 </table>
67 <br />
68 <asp:Button ID="btOK" runat="server" Text="下载" Height="42px" Width="108px" OnClick="btOK_Click" />
69 <asp:Button ID="btCancel" runat="server" OnClick="btCancel_Click" Text="取消/暂停" Height="42px" Width="108px" Enabled="False" /><br />
70 <br />
71 <asp:Label ID="Label1" runat="server" Height="32px" Text="状态: 未开始下载" Width="227px" Font-Bold="True" ForeColor="#8080FF"></asp:Label><br />
72 </td></tr></table>
73 <script language=javascript>
74 mainLoop();
75 </script>
76 </form>
77 </body>
78 </html>
3. 页面后台文件 Default.aspx.cs代码
1 /// <summary>
2 /// Author: [ ChengKing(ZhengJian) ]
3 /// Blog: Http://blog.csdn.net/ChengKing
4 /// 注:从网上找了个优秀代码
5 /// 扩展如下功能:
6 /// 1. 解决一些线程相关的Bug;
7 /// 2.扩展用控制文件实现断点续传功能.
8 /// </summary>
9 public partial class _Default : System.Web.UI.Page
10 {
11 //全局变量
12 private static object _SyncLockObject = new object();
13
14 protected void Page_Load(object sender, EventArgs e)
15 {
16 Utility.RegisterTypeForAjax(typeof(_Default));
17 //this.TextBox1.Text = "http://download.csdn.net/filedown/aHR0cDovL2Rvd25sb2FkMS5jc2RuLm5ldC9kb3duMy8yMDA3MDUwNy8wNzE4MDIwNzY4OC5yYXI=!177258";
18
19
20 this.TextBox1.Text = "https://files.cnblogs.com/ChengKing/智能象棋游戏(T1).rar";
21 }
22 protected void btOK_Click(object sender, EventArgs e)
23 {
24 this.Label1.Text = "状态: 正在下载";
25
26 DownLoadComponent.HttpWebClient x = new DownLoadComponent.HttpWebClient();
27
28 //注册 DataReceive 事件
29 x.DataReceive += new DownLoadComponent.HttpWebClient.DataReceiveEventHandler(this.x_DataReceive);
30 //注册 ExceptionOccurrs 事件
31 x.ExceptionOccurrs += new DownLoadComponent.HttpWebClient.ExceptionEventHandler(this.x_ExceptionOccurrs);
32
33 string Source = this.TextBox1.Text.Trim();
34 string FileName = Source.Substring(Source.LastIndexOf("/") + 1);
35 string Location= System.IO.Path.Combine( this.TextBox2.Text.Trim() , FileName);
36
37 //F: 源服务器文件; _f: 保存路径; 10: 自设定一个文件有几个线程下载.
38 x.DownloadFile(Source,Location , int.Parse(this.TextBox3.Text));
39
40 //Response.Write("正在下载文件");
41 this.btOK.Enabled = false;
42 this.btCancel.Enabled = true;
43 }
44
45 private void x_DataReceive(DownLoadComponent.HttpWebClient Sender, DownLoadComponent.DownLoadEventArgs e)
46 {
47
48 string f = e.DownloadState.FileName;
49 if (e.DownloadState.AttachmentName != null)
50 f = System.IO.Path.GetDirectoryName(f) + @"\" + e.DownloadState.AttachmentName;
51
52 using (System.IO.FileStream sw = new System.IO.FileStream(f, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite, System.IO.FileShare.ReadWrite))
53 {
54 sw.Position = e.DownloadState.Position;
55 sw.Write(e.DownloadState.Data, 0, e.DownloadState.Data.Length);
56 sw.Close();
57 }
58 }
59
60 private void x_ExceptionOccurrs(DownLoadComponent.HttpWebClient Sender, DownLoadComponent.ExceptionEventArgs e)
61 {
62 System.Console.WriteLine(e.Exception.Message);
63 //发生异常重新下载相当于断点续传,你可以自己自行选择处理方式或自行处理
64 DownLoadComponent.HttpWebClient x = new DownLoadComponent.HttpWebClient();
65 x.DataReceive += new DownLoadComponent.HttpWebClient.DataReceiveEventHandler(this.x_DataReceive);
66 //订阅 ExceptionOccurrs 事件
67 //x.ExceptionOccurrs += new DownLoadComponent.HttpWebClient.ExceptionEventHandler(this.x_ExceptionOccurrs);
68
69 x.DownloadFileChunk(e.DownloadState.RequestURL, e.DownloadState.FileName, e.DownloadState.Position, e.DownloadState.Length);
70 e.ExceptionAction = DownLoadComponent.ExceptionActions.Ignore;
71 }
72 protected void btCancel_Click(object sender, EventArgs e)
73 {
74 if (DownLoadComponent.HttpWebClient.threads != null)
75 {
76 foreach (Thread t in DownLoadComponent.HttpWebClient.threads)
77 {
78 if (t.IsAlive)
79 {
80 t.Abort();
81 }
82 }
83
84 DownLoadComponent.HttpWebClient.threads.Clear();
85 }
86 System.Diagnostics.Process myproc = new System.Diagnostics.Process();
87 Process[] procs = (Process[])Process.GetProcessesByName("DW20.exe"); //得到所有打开的进程
88 try
89 {
90 foreach (Process proc in procs)
91 {
92 if (proc.CloseMainWindow() == false)
93 {
94 proc.Kill();
95 }
96 }
97 }
98 catch
99 { }
100 KillAllThreads();
101 this.btOK.Enabled = true;
102 this.btCancel.Enabled = false;
103 GC.Collect();
104
105 }
106
107 /// <summary>
108 /// 定期检查控制文件
109 /// </summary>
110 /// <param name="str"></param>
111 /// <returns>是否还继续监视(1: 正在下载中,继续监视; 0: 表示已经下载完毕,不用再检视)</returns>
112 [AjaxMethod()]// or [AjaxPro.AjaxMethod]
113 public bool CheckControlFiles(string strObjPath)
114 {
115 if (!WhetherDownloadFinished(strObjPath))
116 {
117 return true;
118 }
119 return false;
120 }
121
122 private bool WhetherDownloadFinished(string strObjPath)
123 {
124 DirectoryInfo df = new DirectoryInfo(strObjPath);
125 FileInfo[] fi = (FileInfo[])df.GetFiles("*.txt", SearchOption.TopDirectoryOnly);
126 HttpWebClient hwc = new HttpWebClient();
127 for (int i = 0; i < fi.Length; i++)
128 {
129 if (fi[i].FullName.Length > 12 && fi[i].FullName.Substring(fi[i].FullName.Length - 12) == "_Control.txt")
130 {
131 if (hwc.JudgeControlFileIfFinished(fi[i].FullName) == true)
132 {
133 hwc.DeleteControlFile(fi[i].FullName);
134 KillAllThreads();
135 return true;
136 }
137 }
138 }
139 return false;
140 }
141
142 private void KillAllThreads()
143 {
144 foreach (Thread t in HttpWebClient.threads)
145 {
146 if (t.IsAlive)
147 {
148 t.Abort();
149 }
150 }
151 HttpWebClient.threads.Clear();
152 }
153
154 }
155
2 /// Author: [ ChengKing(ZhengJian) ]
3 /// Blog: Http://blog.csdn.net/ChengKing
4 /// 注:从网上找了个优秀代码
5 /// 扩展如下功能:
6 /// 1. 解决一些线程相关的Bug;
7 /// 2.扩展用控制文件实现断点续传功能.
8 /// </summary>
9 public partial class _Default : System.Web.UI.Page
10 {
11 //全局变量
12 private static object _SyncLockObject = new object();
13
14 protected void Page_Load(object sender, EventArgs e)
15 {
16 Utility.RegisterTypeForAjax(typeof(_Default));
17 //this.TextBox1.Text = "http://download.csdn.net/filedown/aHR0cDovL2Rvd25sb2FkMS5jc2RuLm5ldC9kb3duMy8yMDA3MDUwNy8wNzE4MDIwNzY4OC5yYXI=!177258";
18
19
20 this.TextBox1.Text = "https://files.cnblogs.com/ChengKing/智能象棋游戏(T1).rar";
21 }
22 protected void btOK_Click(object sender, EventArgs e)
23 {
24 this.Label1.Text = "状态: 正在下载";
25
26 DownLoadComponent.HttpWebClient x = new DownLoadComponent.HttpWebClient();
27
28 //注册 DataReceive 事件
29 x.DataReceive += new DownLoadComponent.HttpWebClient.DataReceiveEventHandler(this.x_DataReceive);
30 //注册 ExceptionOccurrs 事件
31 x.ExceptionOccurrs += new DownLoadComponent.HttpWebClient.ExceptionEventHandler(this.x_ExceptionOccurrs);
32
33 string Source = this.TextBox1.Text.Trim();
34 string FileName = Source.Substring(Source.LastIndexOf("/") + 1);
35 string Location= System.IO.Path.Combine( this.TextBox2.Text.Trim() , FileName);
36
37 //F: 源服务器文件; _f: 保存路径; 10: 自设定一个文件有几个线程下载.
38 x.DownloadFile(Source,Location , int.Parse(this.TextBox3.Text));
39
40 //Response.Write("正在下载文件");
41 this.btOK.Enabled = false;
42 this.btCancel.Enabled = true;
43 }
44
45 private void x_DataReceive(DownLoadComponent.HttpWebClient Sender, DownLoadComponent.DownLoadEventArgs e)
46 {
47
48 string f = e.DownloadState.FileName;
49 if (e.DownloadState.AttachmentName != null)
50 f = System.IO.Path.GetDirectoryName(f) + @"\" + e.DownloadState.AttachmentName;
51
52 using (System.IO.FileStream sw = new System.IO.FileStream(f, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite, System.IO.FileShare.ReadWrite))
53 {
54 sw.Position = e.DownloadState.Position;
55 sw.Write(e.DownloadState.Data, 0, e.DownloadState.Data.Length);
56 sw.Close();
57 }
58 }
59
60 private void x_ExceptionOccurrs(DownLoadComponent.HttpWebClient Sender, DownLoadComponent.ExceptionEventArgs e)
61 {
62 System.Console.WriteLine(e.Exception.Message);
63 //发生异常重新下载相当于断点续传,你可以自己自行选择处理方式或自行处理
64 DownLoadComponent.HttpWebClient x = new DownLoadComponent.HttpWebClient();
65 x.DataReceive += new DownLoadComponent.HttpWebClient.DataReceiveEventHandler(this.x_DataReceive);
66 //订阅 ExceptionOccurrs 事件
67 //x.ExceptionOccurrs += new DownLoadComponent.HttpWebClient.ExceptionEventHandler(this.x_ExceptionOccurrs);
68
69 x.DownloadFileChunk(e.DownloadState.RequestURL, e.DownloadState.FileName, e.DownloadState.Position, e.DownloadState.Length);
70 e.ExceptionAction = DownLoadComponent.ExceptionActions.Ignore;
71 }
72 protected void btCancel_Click(object sender, EventArgs e)
73 {
74 if (DownLoadComponent.HttpWebClient.threads != null)
75 {
76 foreach (Thread t in DownLoadComponent.HttpWebClient.threads)
77 {
78 if (t.IsAlive)
79 {
80 t.Abort();
81 }
82 }
83
84 DownLoadComponent.HttpWebClient.threads.Clear();
85 }
86 System.Diagnostics.Process myproc = new System.Diagnostics.Process();
87 Process[] procs = (Process[])Process.GetProcessesByName("DW20.exe"); //得到所有打开的进程
88 try
89 {
90 foreach (Process proc in procs)
91 {
92 if (proc.CloseMainWindow() == false)
93 {
94 proc.Kill();
95 }
96 }
97 }
98 catch
99 { }
100 KillAllThreads();
101 this.btOK.Enabled = true;
102 this.btCancel.Enabled = false;
103 GC.Collect();
104
105 }
106
107 /// <summary>
108 /// 定期检查控制文件
109 /// </summary>
110 /// <param name="str"></param>
111 /// <returns>是否还继续监视(1: 正在下载中,继续监视; 0: 表示已经下载完毕,不用再检视)</returns>
112 [AjaxMethod()]// or [AjaxPro.AjaxMethod]
113 public bool CheckControlFiles(string strObjPath)
114 {
115 if (!WhetherDownloadFinished(strObjPath))
116 {
117 return true;
118 }
119 return false;
120 }
121
122 private bool WhetherDownloadFinished(string strObjPath)
123 {
124 DirectoryInfo df = new DirectoryInfo(strObjPath);
125 FileInfo[] fi = (FileInfo[])df.GetFiles("*.txt", SearchOption.TopDirectoryOnly);
126 HttpWebClient hwc = new HttpWebClient();
127 for (int i = 0; i < fi.Length; i++)
128 {
129 if (fi[i].FullName.Length > 12 && fi[i].FullName.Substring(fi[i].FullName.Length - 12) == "_Control.txt")
130 {
131 if (hwc.JudgeControlFileIfFinished(fi[i].FullName) == true)
132 {
133 hwc.DeleteControlFile(fi[i].FullName);
134 KillAllThreads();
135 return true;
136 }
137 }
138 }
139 return false;
140 }
141
142 private void KillAllThreads()
143 {
144 foreach (Thread t in HttpWebClient.threads)
145 {
146 if (t.IsAlive)
147 {
148 t.Abort();
149 }
150 }
151 HttpWebClient.threads.Clear();
152 }
153
154 }
155
(四).示例代码下载
https://files.cnblogs.com/MVP33650/MultiThreadDownLoadFile.rar
(五).Asp.net 2.0其它相关文章: