借助WebService实现多线程上传文件
在WebService的帮助下,进行多线程上传文件是非常简单。因此我只做个简单的例子,那么如果想要实现此功能的朋友,可以在我的基础上进行扩展。
首先说说服务器端,只需要提供一个能允许多线程写文件的函数即可,具体代码如下。
1 [WebMethod] 2 3 public bool UploadFileData( string FileName, int StartPosition, byte[] bData ) 4 5 { 6 7 string strFullName = Server.MapPath( "Uploads" ) + @""" + FileName; 8 9 FileStream fs = null; 10 11 try 12 13 { 14 15 fs = new FileStream( strFullName, FileMode.OpenOrCreate, 16 17 FileAccess.Write, FileShare.Write ); 18 19 } 20 21 catch( IOException err ) 22 23 { 24 25 Session["ErrorMessage"] = err.Message; 26 27 return false; 28 29 } 30 31 using( fs ) 32 33 { 34 35 fs.Position = StartPosition; 36 37 fs.Write( bData, 0, bData.Length ); 38 39 } 40 41 return true; 42 43 }
其中“Uploads”是在服务程序所在目录下的一个子目录,需要设置ASPNET用户对此目录具有可写权限。
相对于服务器端来说,客户端要稍微复杂一些,因为要牵扯到多线程的问题。为了更好的传递参数,我用一个线程类来完成。具体如下。
1 public delegate void UploadFileData( string FileName, int StartPos, byte[] bData ); 2 3 ///<summary> 4 5 /// FileThread: a class for sub-thread 6 7 ///</summary> 8 9 sealed class FileThread 10 11 { 12 13 private int nStartPos; 14 15 private int nTotalBytes; 16 17 private string strFileName; 18 19 public static UploadFileData UploadHandle; 20 21 ///<summary> 22 23 /// Constructor 24 25 ///</summary> 26 27 ///<param name="StartPos"></param> 28 29 ///<param name="TotalBytes"></param> 30 31 ///<param name="FileName"></param> 32 33 public FileThread( int StartPos, int TotalBytes, string FileName ) 34 35 { 36 37 //Init thread variant 38 39 nStartPos = StartPos; 40 41 nTotalBytes = TotalBytes; 42 43 strFileName = FileName; 44 45 //Only for debug 46 47 Debug.WriteLine( string.Format( "File name:{0} position: {1} total byte:{2}", 48 49 strFileName, nStartPos, nTotalBytes ) ); 50 51 } 52 53 ///<summary> 54 55 /// Sub-thread entry function 56 57 ///</summary> 58 59 ///<param name="stateinfo"></param> 60 61 public void UploadFile( object stateinfo ) 62 63 { 64 65 int nRealRead, nBufferSize; 66 67 const int BUFFER_SIZE = 10240; 68 69 using( FileStream fs = new FileStream( strFileName, 70 71 FileMode.Open, FileAccess.Read, 72 73 FileShare.Read ) ) 74 75 { 76 77 string sName = strFileName.Substring( strFileName.LastIndexOf( """" ) + 1 ); 78 79 byte[] bBuffer = new byte[BUFFER_SIZE];//Init 10k buffer 80 81 fs.Position = nStartPos; 82 83 nRealRead = 0; 84 85 do 86 87 { 88 89 nBufferSize = BUFFER_SIZE; 90 91 if( nRealRead + BUFFER_SIZE > nTotalBytes ) 92 93 nBufferSize = nTotalBytes - nRealRead; 94 95 nBufferSize = fs.Read( bBuffer, 0, nBufferSize ); 96 97 if( nBufferSize == BUFFER_SIZE ) 98 99 UploadHandle( sName, 100 101 nRealRead + nStartPos, 102 103 bBuffer ); 104 105 else if( nBufferSize > 0 ) 106 107 { 108 109 //Copy data 110 111 byte[] bytData = new byte[nBufferSize]; 112 113 Array.Copy( bBuffer,0, bytData, 0, nBufferSize ); 114 115 UploadHandle( sName, 116 117 nRealRead + nStartPos, 118 119 bytData ); 120 121 } 122 123 nRealRead += nBufferSize; 124 125 } 126 127 while( nRealRead < nTotalBytes ); 128 129 } 130 131 //Release signal 132 133 ManualResetEvent mr = stateinfo as ManualResetEvent; 134 135 if( mr != null ) 136 137 mr.Set(); 138 139 } 140 141 } 142 143 144 145 那么在执行的时候,要创建线程类对象,并为每一个每个线程设置一个信号量,从而能在所有线程都结束的时候得到通知,大致的代码如下。 146 147 FileInfo fi = new FileInfo( txtFileName.Text ); 148 149 if( fi.Exists ) 150 151 { 152 153 btnUpload.Enabled = false;//Avoid upload twice 154 155 //Init signals 156 157 ManualResetEvent[] events = new ManualResetEvent[5]; 158 159 //Devide blocks 160 161 int nTotalBytes = (int)( fi.Length / 5 ); 162 163 for( int i = 0; i < 5; i++ ) 164 165 { 166 167 events[i] = new ManualResetEvent( false ); 168 169 FileThread thdSub = new FileThread( 170 171 i * nTotalBytes, 172 173 ( fi.Length - i * nTotalBytes ) > nTotalBytes ? nTotalBytes:(int)( fi.Length - i * nTotalBytes ), 174 175 fi.FullName ); 176 177 ThreadPool.QueueUserWorkItem( new WaitCallback( thdSub.UploadFile ), events[i] ); 178 179 } 180 181 //Wait for threads finished 182 183 WaitHandle.WaitAll( events ); 184 185 //Reset button status 186 187 btnUpload.Enabled = true; 188 189 }
总体来说,程序还是相对比较简单,而我也只是做了个简单例子而已,一些细节都没有进行处理
本来想打包提供给大家下载,没想到CSDN的Blog对于这点做的太差,老是异常。
如下是客户端的完整代码。
1 //--------------------------- Multi-thread Upload Demo --------------------------------------- 2 3 4 5 //-------------------------------------------------------------------------------------------- 6 7 8 9 //---File: frmUpload 10 11 12 13 //---Description: The multi-thread upload form file to demenstrate howto use multi-thread to 14 15 16 17 // upload files 18 19 20 21 //---Author: Knight 22 23 24 25 //---Date: Oct.12, 2006 26 27 28 29 //-------------------------------------------------------------------------------------------- 30 31 32 33 //---------------------------{Multi-thread Upload Demo}--------------------------------------- 34 35 36 37 using System; 38 39 40 41 using System.Drawing; 42 43 44 45 using System.Collections; 46 47 48 49 using System.ComponentModel; 50 51 52 53 using System.Windows.Forms; 54 55 56 57 using System.Data; 58 59 60 61 namespace CSUpload 62 63 64 65 { 66 67 68 69 using System.IO; 70 71 72 73 using System.Diagnostics; 74 75 76 77 using System.Threading; 78 79 80 81 using WSUploadFile;//Web-service reference namespace 82 83 84 85 ///<summary> 86 87 88 89 /// Summary description for Form1. 90 91 92 93 ///</summary> 94 95 96 97 public class frmUpload : System.Windows.Forms.Form 98 99 100 101 { 102 103 104 105 private System.Windows.Forms.TextBox txtFileName; 106 107 108 109 private System.Windows.Forms.Button btnBrowse; 110 111 112 113 private System.Windows.Forms.Button btnUpload; 114 115 116 117 ///<summary> 118 119 120 121 /// Required designer variable. 122 123 124 125 ///</summary> 126 127 128 129 private System.ComponentModel.Container components = null; 130 131 132 133 public frmUpload() 134 135 136 137 { 138 139 140 141 // 142 143 144 145 // Required for Windows Form Designer support 146 147 148 149 // 150 151 152 153 InitializeComponent(); 154 155 156 157 // 158 159 160 161 // TODO: Add any constructor code after InitializeComponent call 162 163 164 165 // 166 167 168 169 } 170 171 172 173 ///<summary> 174 175 176 177 /// Clean up any resources being used. 178 179 180 181 ///</summary> 182 183 184 185 protected override void Dispose( bool disposing ) 186 187 188 189 { 190 191 192 193 if( disposing ) 194 195 196 197 { 198 199 200 201 if (components != null) 202 203 204 205 { 206 207 208 209 components.Dispose(); 210 211 212 213 } 214 215 216 217 } 218 219 220 221 base.Dispose( disposing ); 222 223 224 225 } 226 227 228 229 #region Windows Form Designer generated code 230 231 232 233 ///<summary> 234 235 236 237 /// Required method for Designer support - do not modify 238 239 240 241 /// the contents of this method with the code editor. 242 243 244 245 ///</summary> 246 247 248 249 private void InitializeComponent() 250 251 252 253 { 254 255 256 257 this.txtFileName = new System.Windows.Forms.TextBox(); 258 259 260 261 this.btnBrowse = new System.Windows.Forms.Button(); 262 263 264 265 this.btnUpload = new System.Windows.Forms.Button(); 266 267 268 269 this.SuspendLayout(); 270 271 272 273 // 274 275 276 277 // txtFileName 278 279 280 281 // 282 283 284 285 this.txtFileName.Location = new System.Drawing.Point(16, 24); 286 287 288 289 this.txtFileName.Name = "txtFileName"; 290 291 292 293 this.txtFileName.Size = new System.Drawing.Size(248, 20); 294 295 296 297 this.txtFileName.TabIndex = 0; 298 299 300 301 this.txtFileName.Text = ""; 302 303 304 305 // 306 307 308 309 // btnBrowse 310 311 312 313 // 314 315 316 317 this.btnBrowse.Location = new System.Drawing.Point(272, 24); 318 319 320 321 this.btnBrowse.Name = "btnBrowse"; 322 323 324 325 this.btnBrowse.TabIndex = 1; 326 327 328 329 this.btnBrowse.Text = "&Browse..."; 330 331 332 333 this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click); 334 335 336 337 // 338 339 340 341 // btnUpload 342 343 344 345 // 346 347 348 349 this.btnUpload.Location = new System.Drawing.Point(272, 56); 350 351 352 353 this.btnUpload.Name = "btnUpload"; 354 355 356 357 this.btnUpload.TabIndex = 2; 358 359 360 361 this.btnUpload.Text = "&Upload"; 362 363 364 365 this.btnUpload.Click += new System.EventHandler(this.btnUpload_Click); 366 367 368 369 // 370 371 372 373 // frmUpload 374 375 376 377 // 378 379 380 381 this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); 382 383 384 385 this.ClientSize = new System.Drawing.Size(370, 111); 386 387 388 389 this.Controls.Add(this.btnUpload); 390 391 392 393 this.Controls.Add(this.btnBrowse); 394 395 396 397 this.Controls.Add(this.txtFileName); 398 399 400 401 this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; 402 403 404 405 this.MaximizeBox = false; 406 407 408 409 this.Name = "frmUpload"; 410 411 412 413 this.Text = "Upload"; 414 415 416 417 this.Load += new System.EventHandler(this.frmUpload_Load); 418 419 420 421 this.ResumeLayout(false); 422 423 424 425 } 426 427 428 429 #endregion 430 431 432 433 ///<summary> 434 435 436 437 /// The main entry point for the application. 438 439 440 441 ///</summary> 442 443 444 445 static void Main() 446 447 448 449 { 450 451 452 453 Application.Run(new frmUpload()); 454 455 456 457 } 458 459 460 461 private FileUpload myUpload = new FileUpload(); 462 463 464 465 private void UploadData( string FileName, int StartPos, byte[] bData ) 466 467 468 469 { 470 471 472 473 //Call web service upload 474 475 476 477 myUpload.UploadFileData( FileName, StartPos, bData ); 478 479 480 481 } 482 483 484 485 private void btnUpload_Click(object sender, System.EventArgs e) 486 487 488 489 { 490 491 492 493 FileInfo fi = new FileInfo( txtFileName.Text ); 494 495 496 497 if( fi.Exists ) 498 499 500 501 { 502 503 504 505 btnUpload.Enabled = false;//Avoid upload twice 506 507 508 509 //Init signals 510 511 512 513 ManualResetEvent[] events = new ManualResetEvent[5]; 514 515 516 517 //Devide blocks 518 519 520 521 int nTotalBytes = (int)( fi.Length / 5 ); 522 523 524 525 for( int i = 0; i < 5; i++ ) 526 527 528 529 { 530 531 532 533 events[i] = new ManualResetEvent( false ); 534 535 536 537 FileThread thdSub = new FileThread( 538 539 540 541 i * nTotalBytes, 542 543 544 545 ( fi.Length - i * nTotalBytes ) > nTotalBytes ? nTotalBytes:(int)( fi.Length - i * nTotalBytes ), 546 547 548 549 fi.FullName ); 550 551 552 553 ThreadPool.QueueUserWorkItem( new WaitCallback( thdSub.UploadFile ), events[i] ); 554 555 556 557 } 558 559 560 561 //Wait for threads finished 562 563 564 565 WaitHandle.WaitAll( events ); 566 567 568 569 //Reset button status 570 571 572 573 btnUpload.Enabled = true; 574 575 576 577 } 578 579 580 581 582 583 584 585 } 586 587 588 589 private void frmUpload_Load(object sender, System.EventArgs e) 590 591 592 593 { 594 595 596 597 FileThread.UploadHandle = new UploadFileData( this.UploadData ); 598 599 600 601 } 602 603 604 605 private void btnBrowse_Click(object sender, System.EventArgs e) 606 607 608 609 { 610 611 612 613 if( fileOpen.ShowDialog() == DialogResult.OK ) 614 615 616 617 txtFileName.Text = fileOpen.FileName; 618 619 620 621 } 622 623 624 625 private OpenFileDialog fileOpen = new OpenFileDialog(); 626 627 628 629 630 631 632 633 } 634 635 636 637 public delegate void UploadFileData( string FileName, int StartPos, byte[] bData ); 638 639 640 641 ///<summary> 642 643 644 645 /// FileThread: a class for sub-thread 646 647 648 649 ///</summary> 650 651 652 653 sealed class FileThread 654 655 656 657 { 658 659 660 661 private int nStartPos; 662 663 664 665 private int nTotalBytes; 666 667 668 669 private string strFileName; 670 671 672 673 public static UploadFileData UploadHandle; 674 675 676 677 ///<summary> 678 679 680 681 /// Constructor 682 683 684 685 ///</summary> 686 687 688 689 ///<param name="StartPos"></param> 690 691 692 693 ///<param name="TotalBytes"></param> 694 695 696 697 ///<param name="FileName"></param> 698 699 700 701 public FileThread( int StartPos, int TotalBytes, string FileName ) 702 703 704 705 { 706 707 708 709 //Init thread variant 710 711 712 713 nStartPos = StartPos; 714 715 716 717 nTotalBytes = TotalBytes; 718 719 720 721 strFileName = FileName; 722 723 724 725 //Only for debug 726 727 728 729 Debug.WriteLine( string.Format( "File name:{0} position: {1} total byte:{2}", 730 731 732 733 strFileName, nStartPos, nTotalBytes ) ); 734 735 736 737 } 738 739 740 741 ///<summary> 742 743 744 745 /// Sub-thread entry function 746 747 748 749 ///</summary> 750 751 752 753 ///<param name="stateinfo"></param> 754 755 756 757 public void UploadFile( object stateinfo ) 758 759 760 761 { 762 763 764 765 int nRealRead, nBufferSize; 766 767 768 769 const int BUFFER_SIZE = 10240; 770 771 772 773 using( FileStream fs = new FileStream( strFileName, 774 775 776 777 FileMode.Open, FileAccess.Read, 778 779 780 781 FileShare.Read ) ) 782 783 784 785 { 786 787 788 789 string sName = strFileName.Substring( strFileName.LastIndexOf( """" ) + 1 ); 790 791 792 793 byte[] bBuffer = new byte[BUFFER_SIZE];//Init 10k buffer 794 795 796 797 fs.Position = nStartPos; 798 799 800 801 nRealRead = 0; 802 803 804 805 do 806 807 808 809 { 810 811 812 813 nBufferSize = BUFFER_SIZE; 814 815 816 817 if( nRealRead + BUFFER_SIZE > nTotalBytes ) 818 819 820 821 nBufferSize = nTotalBytes - nRealRead; 822 823 824 825 nBufferSize = fs.Read( bBuffer, 0, nBufferSize ); 826 827 828 829 if( nBufferSize == BUFFER_SIZE ) 830 831 832 833 UploadHandle( sName, 834 835 836 837 nRealRead + nStartPos, 838 839 840 841 bBuffer ); 842 843 844 845 else if( nBufferSize > 0 ) 846 847 848 849 { 850 851 852 853 //Copy data 854 855 856 857 byte[] bytData = new byte[nBufferSize]; 858 859 860 861 Array.Copy( bBuffer,0, bytData, 0, nBufferSize ); 862 863 864 865 UploadHandle( sName, 866 867 868 869 nRealRead + nStartPos, 870 871 872 873 bytData ); 874 875 876 877 } 878 nRealRead += nBufferSize; 879 } 880 while( nRealRead < nTotalBytes ); 881 } 882 883 //Release signal 884 885 ManualResetEvent mr = stateinfo as ManualResetEvent; 886 887 if( mr != null ) 888 889 mr.Set(); 890 } 891 892 } 893 894 }
浙公网安备 33010602011771号