您的位置:首页 > 其它

借助WebService实现多线程上传文件

2007-05-21 17:04 453 查看
借助WebService实现多线程上传文件

在WebService的帮助下,进行多线程上传文件是非常简单。因此我只做个简单的例子,那么如果想要实现此功能的朋友,可以在我的基础上进行扩展。

首先说说服务器端,只需要提供一个能允许多线程写文件的函数即可,具体代码如下。
[align=left][WebMethod][/align]
[align=left]public bool UploadFileData( string FileName, int StartPosition, byte[] bData )[/align]
[align=left]{[/align]
[align=left] string strFullName = Server.MapPath( "Uploads" ) + @"/" + FileName;[/align]
[align=left] FileStream fs = null;[/align]
[align=left] try[/align]
[align=left] {[/align]
[align=left] fs = new FileStream( strFullName, FileMode.OpenOrCreate, [/align]
[align=left] FileAccess.Write, FileShare.Write );[/align]
[align=left] }[/align]
[align=left] catch( IOException err )[/align]
[align=left] {[/align]
[align=left] Session["ErrorMessage"] = err.Message;[/align]
[align=left] return false;[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] using( fs )[/align]
[align=left] {[/align]
[align=left] fs.Position = StartPosition;[/align]
[align=left] fs.Write( bData, 0, bData.Length );[/align]
[align=left] }[/align]
[align=left] return true;[/align]
[align=left]}[/align]

其中“Uploads”是在服务程序所在目录下的一个子目录,需要设置ASPNET用户对此目录具有可写权限。

相对于服务器端来说,客户端要稍微复杂一些,因为要牵扯到多线程的问题。为了更好的传递参数,我用一个线程类来完成。具体如下。
[align=left] public delegate void UploadFileData( string FileName, int StartPos, byte[] bData );[/align]
[align=left] [/align]
[align=left] ///<summary>[/align]
[align=left] /// FileThread: a class for sub-thread[/align]
[align=left] ///</summary>[/align]
[align=left] sealed class FileThread[/align]
[align=left] {[/align]
[align=left] private int nStartPos;[/align]
[align=left] private int nTotalBytes;[/align]
[align=left] private string strFileName;[/align]
[align=left] public static UploadFileData UploadHandle;[/align]
[align=left] [/align]
[align=left] ///<summary>[/align]
[align=left] /// Constructor[/align]
[align=left] ///</summary>[/align]
[align=left] ///<param name="StartPos"></param>[/align]
[align=left] ///<param name="TotalBytes"></param>[/align]
[align=left] ///<param name="FileName"></param>[/align]
[align=left] public FileThread( int StartPos, int TotalBytes, string FileName )[/align]
[align=left] {[/align]
[align=left] //Init thread variant[/align]
[align=left] nStartPos = StartPos;[/align]
[align=left] nTotalBytes = TotalBytes;[/align]
[align=left] strFileName = FileName;[/align]
[align=left] [/align]
[align=left] //Only for debug[/align]
[align=left] Debug.WriteLine( string.Format( "File name:{0} position: {1} total byte:{2}",[/align]
[align=left] strFileName, nStartPos, nTotalBytes ) );[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] ///<summary>[/align]
[align=left] /// Sub-thread entry function [/align]
[align=left] ///</summary>[/align]
[align=left] ///<param name="stateinfo"></param>[/align]
[align=left] public void UploadFile( object stateinfo )[/align]
[align=left] {[/align]
[align=left] int nRealRead, nBufferSize;[/align]
[align=left] const int BUFFER_SIZE = 10240;[/align]
[align=left] [/align]
[align=left] using( FileStream fs = new FileStream( strFileName,[/align]
[align=left] FileMode.Open, FileAccess.Read,[/align]
[align=left] FileShare.Read ) )[/align]
[align=left] {[/align]
[align=left] string sName = strFileName.Substring( strFileName.LastIndexOf( "//" ) + 1 );[/align]
[align=left] byte[] bBuffer = new byte[BUFFER_SIZE];//Init 10k buffer[/align]
[align=left] fs.Position = nStartPos;[/align]
[align=left] nRealRead = 0;[/align]
[align=left] do[/align]
[align=left] {[/align]
[align=left] nBufferSize = BUFFER_SIZE;[/align]
[align=left] if( nRealRead + BUFFER_SIZE > nTotalBytes )[/align]
[align=left] nBufferSize = nTotalBytes - nRealRead;[/align]
[align=left] [/align]
[align=left] nBufferSize = fs.Read( bBuffer, 0, nBufferSize );[/align]
[align=left] if( nBufferSize == BUFFER_SIZE )[/align]
[align=left] UploadHandle( sName,[/align]
[align=left] nRealRead + nStartPos,[/align]
[align=left] bBuffer );[/align]
[align=left] else if( nBufferSize > 0 )[/align]
[align=left] {[/align]
[align=left] //Copy data [/align]
[align=left] byte[] bytData = new byte[nBufferSize];[/align]
[align=left] Array.Copy( bBuffer,0, bytData, 0, nBufferSize );[/align]
[align=left] [/align]
[align=left] UploadHandle( sName,[/align]
[align=left] nRealRead + nStartPos,[/align]
[align=left] bytData );[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] nRealRead += nBufferSize;[/align]
[align=left] }[/align]
[align=left] while( nRealRead < nTotalBytes );[/align]
[align=left] }[/align]
[align=left] //Release signal[/align]
[align=left] ManualResetEvent mr = stateinfo as ManualResetEvent;[/align]
[align=left] if( mr != null )[/align]
[align=left] mr.Set();[/align]
[align=left] }[/align]
[align=left] }[/align]

那么在执行的时候,要创建线程类对象,并为每一个每个线程设置一个信号量,从而能在所有线程都结束的时候得到通知,大致的代码如下。
[align=left] FileInfo fi = new FileInfo( txtFileName.Text );[/align]
[align=left] if( fi.Exists )[/align]
[align=left] {[/align]
[align=left] btnUpload.Enabled = false;//Avoid upload twice[/align]
[align=left] [/align]
[align=left] //Init signals[/align]
[align=left] ManualResetEvent[] events = new ManualResetEvent[5];[/align]
[align=left] [/align]
[align=left] //Devide blocks[/align]
[align=left] int nTotalBytes = (int)( fi.Length / 5 );[/align]
[align=left] for( int i = 0; i < 5; i++ )[/align]
[align=left] {[/align]
[align=left] events[i] = new ManualResetEvent( false );[/align]
[align=left] FileThread thdSub = new FileThread( [/align]
[align=left] i * nTotalBytes,[/align]
[align=left] ( fi.Length - i * nTotalBytes ) > nTotalBytes ? nTotalBytes:(int)( fi.Length - i * nTotalBytes ),[/align]
[align=left] fi.FullName );[/align]
[align=left] ThreadPool.QueueUserWorkItem( new WaitCallback( thdSub.UploadFile ), events[i] );[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] //Wait for threads finished[/align]
[align=left] WaitHandle.WaitAll( events );[/align]
[align=left] [/align]
[align=left] //Reset button status[/align]
[align=left] btnUpload.Enabled = true;[/align]
[align=left] }[/align]

总体来说,程序还是相对比较简单,而我也只是做了个简单例子而已,一些细节都没有进行处理。

本来想打包提供给大家下载,没想到CSDN的Blog对于这点做的太差,老是异常。
如下是客户端的完整代码。
[align=left]//--------------------------- Multi-thread Upload Demo ---------------------------------------[/align]
[align=left]//--------------------------------------------------------------------------------------------[/align]
[align=left]//---File: frmUpload[/align]
[align=left]//---Description: The multi-thread upload form file to demenstrate howto use multi-thread to [/align]
[align=left]// upload files[/align]
[align=left]//---Author: Knight[/align]
[align=left]//---Date: Oct.12, 2006[/align]
[align=left]//--------------------------------------------------------------------------------------------[/align]
[align=left]//---------------------------{Multi-thread Upload Demo}---------------------------------------[/align]
[align=left]using System;[/align]
[align=left]using System.Drawing;[/align]
[align=left]using System.Collections;[/align]
[align=left]using System.ComponentModel;[/align]
[align=left]using System.Windows.Forms;[/align]
[align=left]using System.Data;[/align]
[align=left] [/align]
[align=left]namespace CSUpload[/align]
[align=left]{[/align]
[align=left] using System.IO;[/align]
[align=left] using System.Diagnostics;[/align]
[align=left] using System.Threading;[/align]
[align=left] using WSUploadFile;//Web-service reference namespace[/align]
[align=left] [/align]
[align=left] ///<summary>[/align]
[align=left] /// Summary description for Form1.[/align]
[align=left] ///</summary>[/align]
[align=left] public class frmUpload : System.Windows.Forms.Form[/align]
[align=left] {[/align]
[align=left] private System.Windows.Forms.TextBox txtFileName;[/align]
[align=left] private System.Windows.Forms.Button btnBrowse;[/align]
[align=left] private System.Windows.Forms.Button btnUpload;[/align]
[align=left] ///<summary>[/align]
[align=left] /// Required designer variable.[/align]
[align=left] ///</summary>[/align]
[align=left] private System.ComponentModel.Container components = null;[/align]
[align=left] [/align]
[align=left] public frmUpload()[/align]
[align=left] {[/align]
[align=left] //[/align]
[align=left] // Required for Windows Form Designer support[/align]
[align=left] //[/align]
[align=left] InitializeComponent();[/align]
[align=left] [/align]
[align=left] //[/align]
[align=left] // TODO: Add any constructor code after InitializeComponent call[/align]
[align=left] //[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] ///<summary>[/align]
[align=left] /// Clean up any resources being used.[/align]
[align=left] ///</summary>[/align]
[align=left] protected override void Dispose( bool disposing )[/align]
[align=left] {[/align]
[align=left] if( disposing )[/align]
[align=left] {[/align]
[align=left] if (components != null) [/align]
[align=left] {[/align]
[align=left] components.Dispose();[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] base.Dispose( disposing );[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] #region Windows Form Designer generated code[/align]
[align=left] ///<summary>[/align]
[align=left] /// Required method for Designer support - do not modify[/align]
[align=left] /// the contents of this method with the code editor.[/align]
[align=left] ///</summary>[/align]
[align=left] private void InitializeComponent()[/align]
[align=left] {[/align]
[align=left] this.txtFileName = new System.Windows.Forms.TextBox();[/align]
[align=left] this.btnBrowse = new System.Windows.Forms.Button();[/align]
[align=left] this.btnUpload = new System.Windows.Forms.Button();[/align]
[align=left] this.SuspendLayout();[/align]
[align=left] // [/align]
[align=left] // txtFileName[/align]
[align=left] // [/align]
[align=left] this.txtFileName.Location = new System.Drawing.Point(16, 24);[/align]
[align=left] this.txtFileName.Name = "txtFileName";[/align]
[align=left] this.txtFileName.Size = new System.Drawing.Size(248, 20);[/align]
[align=left] this.txtFileName.TabIndex = 0;[/align]
[align=left] this.txtFileName.Text = "";[/align]
[align=left] // [/align]
[align=left] // btnBrowse[/align]
[align=left] // [/align]
[align=left] this.btnBrowse.Location = new System.Drawing.Point(272, 24);[/align]
[align=left] this.btnBrowse.Name = "btnBrowse";[/align]
[align=left] this.btnBrowse.TabIndex = 1;[/align]
[align=left] this.btnBrowse.Text = "&Browse...";[/align]
[align=left] this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click);[/align]
[align=left] // [/align]
[align=left] // btnUpload[/align]
[align=left] // [/align]
[align=left] this.btnUpload.Location = new System.Drawing.Point(272, 56);[/align]
[align=left] this.btnUpload.Name = "btnUpload";[/align]
[align=left] this.btnUpload.TabIndex = 2;[/align]
[align=left] this.btnUpload.Text = "&Upload";[/align]
[align=left] this.btnUpload.Click += new System.EventHandler(this.btnUpload_Click);[/align]
[align=left] // [/align]
[align=left] // frmUpload[/align]
[align=left] // [/align]
[align=left] this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);[/align]
[align=left] this.ClientSize = new System.Drawing.Size(370, 111);[/align]
[align=left] this.Controls.Add(this.btnUpload);[/align]
[align=left] this.Controls.Add(this.btnBrowse);[/align]
[align=left] this.Controls.Add(this.txtFileName);[/align]
[align=left] this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;[/align]
[align=left] this.MaximizeBox = false;[/align]
[align=left] this.Name = "frmUpload";[/align]
[align=left] this.Text = "Upload";[/align]
[align=left] this.Load += new System.EventHandler(this.frmUpload_Load);[/align]
[align=left] this.ResumeLayout(false);[/align]
[align=left] [/align]
[align=left] }[/align]
[align=left] #endregion[/align]
[align=left] [/align]
[align=left] ///<summary>[/align]
[align=left] /// The main entry point for the application.[/align]
[align=left] ///</summary>[/align]
[align=left] static void Main() [/align]
[align=left] {[/align]
[align=left] Application.Run(new frmUpload());[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] private FileUpload myUpload = new FileUpload();[/align]
[align=left] private void UploadData( string FileName, int StartPos, byte[] bData )[/align]
[align=left] {[/align]
[align=left] //Call web service upload[/align]
[align=left] myUpload.UploadFileData( FileName, StartPos, bData );[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] private void btnUpload_Click(object sender, System.EventArgs e)[/align]
[align=left] {[/align]
[align=left] FileInfo fi = new FileInfo( txtFileName.Text );[/align]
[align=left] if( fi.Exists )[/align]
[align=left] {[/align]
[align=left] btnUpload.Enabled = false;//Avoid upload twice[/align]
[align=left] [/align]
[align=left] //Init signals[/align]
[align=left] ManualResetEvent[] events = new ManualResetEvent[5];[/align]
[align=left] [/align]
[align=left] //Devide blocks[/align]
[align=left] int nTotalBytes = (int)( fi.Length / 5 );[/align]
[align=left] for( int i = 0; i < 5; i++ )[/align]
[align=left] {[/align]
[align=left] events[i] = new ManualResetEvent( false );[/align]
[align=left] FileThread thdSub = new FileThread( [/align]
[align=left] i * nTotalBytes,[/align]
[align=left] ( fi.Length - i * nTotalBytes ) > nTotalBytes ? nTotalBytes:(int)( fi.Length - i * nTotalBytes ),[/align]
[align=left] fi.FullName );[/align]
[align=left] ThreadPool.QueueUserWorkItem( new WaitCallback( thdSub.UploadFile ), events[i] );[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] //Wait for threads finished[/align]
[align=left] WaitHandle.WaitAll( events );[/align]
[align=left] [/align]
[align=left] //Reset button status[/align]
[align=left] btnUpload.Enabled = true;[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] private void frmUpload_Load(object sender, System.EventArgs e)[/align]
[align=left] {[/align]
[align=left] FileThread.UploadHandle = new UploadFileData( this.UploadData );[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] private void btnBrowse_Click(object sender, System.EventArgs e)[/align]
[align=left] {[/align]
[align=left] if( fileOpen.ShowDialog() == DialogResult.OK )[/align]
[align=left] txtFileName.Text = fileOpen.FileName;[/align]
[align=left] }[/align]
[align=left] private OpenFileDialog fileOpen = new OpenFileDialog();[/align]
[align=left] [/align]
[align=left] [/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] public delegate void UploadFileData( string FileName, int StartPos, byte[] bData );[/align]
[align=left] [/align]
[align=left] ///<summary>[/align]
[align=left] /// FileThread: a class for sub-thread[/align]
[align=left] ///</summary>[/align]
[align=left] sealed class FileThread[/align]
[align=left] {[/align]
[align=left] private int nStartPos;[/align]
[align=left] private int nTotalBytes;[/align]
[align=left] private string strFileName;[/align]
[align=left] public static UploadFileData UploadHandle;[/align]
[align=left] [/align]
[align=left] ///<summary>[/align]
[align=left] /// Constructor[/align]
[align=left] ///</summary>[/align]
[align=left] ///<param name="StartPos"></param>[/align]
[align=left] ///<param name="TotalBytes"></param>[/align]
[align=left] ///<param name="FileName"></param>[/align]
[align=left] public FileThread( int StartPos, int TotalBytes, string FileName )[/align]
[align=left] {[/align]
[align=left] //Init thread variant[/align]
[align=left] nStartPos = StartPos;[/align]
[align=left] nTotalBytes = TotalBytes;[/align]
[align=left] strFileName = FileName;[/align]
[align=left] [/align]
[align=left] //Only for debug[/align]
[align=left] Debug.WriteLine( string.Format( "File name:{0} position: {1} total byte:{2}",[/align]
[align=left] strFileName, nStartPos, nTotalBytes ) );[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] ///<summary>[/align]
[align=left] /// Sub-thread entry function [/align]
[align=left] ///</summary>[/align]
[align=left] ///<param name="stateinfo"></param>[/align]
[align=left] public void UploadFile( object stateinfo )[/align]
[align=left] {[/align]
[align=left] int nRealRead, nBufferSize;[/align]
[align=left] const int BUFFER_SIZE = 10240;[/align]
[align=left] [/align]
[align=left] using( FileStream fs = new FileStream( strFileName,[/align]
[align=left] FileMode.Open, FileAccess.Read,[/align]
[align=left] FileShare.Read ) )[/align]
[align=left] {[/align]
[align=left] string sName = strFileName.Substring( strFileName.LastIndexOf( "//" ) + 1 );[/align]
[align=left] byte[] bBuffer = new byte[BUFFER_SIZE];//Init 10k buffer[/align]
[align=left] fs.Position = nStartPos;[/align]
[align=left] nRealRead = 0;[/align]
[align=left] do[/align]
[align=left] {[/align]
[align=left] nBufferSize = BUFFER_SIZE;[/align]
[align=left] if( nRealRead + BUFFER_SIZE > nTotalBytes )[/align]
[align=left] nBufferSize = nTotalBytes - nRealRead;[/align]
[align=left] [/align]
[align=left] nBufferSize = fs.Read( bBuffer, 0, nBufferSize );[/align]
[align=left] if( nBufferSize == BUFFER_SIZE )[/align]
[align=left] UploadHandle( sName,[/align]
[align=left] nRealRead + nStartPos,[/align]
[align=left] bBuffer );[/align]
[align=left] else if( nBufferSize > 0 )[/align]
[align=left] {[/align]
[align=left] //Copy data [/align]
[align=left] byte[] bytData = new byte[nBufferSize];[/align]
[align=left] Array.Copy( bBuffer,0, bytData, 0, nBufferSize );[/align]
[align=left] [/align]
[align=left] UploadHandle( sName,[/align]
[align=left] nRealRead + nStartPos,[/align]
[align=left] bytData );[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] nRealRead += nBufferSize;[/align]
[align=left] }[/align]
[align=left] while( nRealRead < nTotalBytes );[/align]
[align=left] }[/align]
[align=left] //Release signal[/align]
[align=left] ManualResetEvent mr = stateinfo as ManualResetEvent;[/align]
[align=left] if( mr != null )[/align]
[align=left] mr.Set();[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left]}[/align]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: