<%-- 最新动态 Begin --%>
|
|
|
|
|
|
<%-- 最新动态 End --%>
|
<%-- 最新动态 Begin --%>
|
|
|
|
|
|
<%-- 最新动态 End --%>
|
<%-- 最新动态 Begin --%>
|
|
|
|
|
|
<%-- 最新动态 End --%>
|
|
|
Asp.net 2.0 文件下载[支持多线程, 断点续传功能] |
 |
|
 |
本文由中国C#技术学习中心整理 如果你对本文有不明之处请到技术论坛讨论!
最近做了个C/S文件下载工具, 支持多任务, 多线程和断点续传功能. 其中部分代码是从网上找来的, 自己改了
许多Thread 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.页面 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>
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 = "http://www.cnblogs.com/Files/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
本文由中国C#技术学习中心整理 如果你对本文有不明之处请到技术论坛讨论!
|
|