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

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

 

首先说说服务器端,只需要提供一个能允许多线程写文件的函数即可,具体代码如下。

[WebMethod]

public bool UploadFileData( string FileName, int StartPosition, byte[] bData )

{

    string strFullName = Server.MapPath( "Uploads" ) + @""" + FileName;

    FileStream fs = null;

    try

    {

        fs = new FileStream( strFullName, FileMode.OpenOrCreate,

            FileAccess.Write, FileShare.Write );

    }

    catch( IOException err )

    {

        Session["ErrorMessage"] = err.Message;

        return false;

    }

    using( fs )

    {

        fs.Position = StartPosition;

        fs.Write( bData, 0, bData.Length );

    }

    return true;

}

 

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

 

相对于服务器端来说,客户端要稍微复杂一些,因为要牵扯到多线程的问题。为了更好的传递参数,我用一个线程类来完成。具体如下。

    public delegate void UploadFileData( string FileName, int StartPos, byte[] bData );

    ///<summary>

    /// FileThread: a class for sub-thread

    ///</summary>

    sealed class FileThread

    {

        private int nStartPos;

        private int nTotalBytes;

        private string strFileName;

        public static UploadFileData UploadHandle;

        ///<summary>

        /// Constructor

        ///</summary>

        ///<param name="StartPos"></param>

        ///<param name="TotalBytes"></param>

        ///<param name="FileName"></param>

        public FileThread( int StartPos, int TotalBytes, string FileName )

        {

            //Init thread variant

            nStartPos = StartPos;

            nTotalBytes = TotalBytes;

            strFileName = FileName;

            //Only for debug

            Debug.WriteLine( string.Format( "File name:{0} position: {1} total byte:{2}",

                strFileName, nStartPos, nTotalBytes ) );

        }

        ///<summary>

        /// Sub-thread entry function

        ///</summary>

        ///<param name="stateinfo"></param>

        public void UploadFile( object stateinfo )

        {

            int nRealRead, nBufferSize;

            const int BUFFER_SIZE = 10240;

            using( FileStream fs = new FileStream( strFileName,

                       FileMode.Open, FileAccess.Read,

                       FileShare.Read ) )

            {

                string sName = strFileName.Substring( strFileName.LastIndexOf( """" ) + 1 );

                byte[] bBuffer = new byte[BUFFER_SIZE];//Init 10k buffer

                fs.Position = nStartPos;

                nRealRead = 0;

                do

                {

                    nBufferSize = BUFFER_SIZE;

                    if( nRealRead + BUFFER_SIZE > nTotalBytes )

                        nBufferSize = nTotalBytes - nRealRead;

                    nBufferSize = fs.Read( bBuffer, 0, nBufferSize );

                    if( nBufferSize == BUFFER_SIZE )

                        UploadHandle( sName,

                            nRealRead + nStartPos,

                            bBuffer );

                    else if( nBufferSize > 0 )

                    {

                        //Copy data

                        byte[] bytData = new byte[nBufferSize];

                        Array.Copy( bBuffer,0, bytData, 0, nBufferSize );

                        UploadHandle( sName,

                            nRealRead + nStartPos,

                            bytData );

                    }

                    nRealRead += nBufferSize;

                }

                while( nRealRead < nTotalBytes );

            }

            //Release signal

            ManualResetEvent mr = stateinfo as ManualResetEvent;

            if( mr != null )

                mr.Set();

        }

    }

 

那么在执行的时候,要创建线程类对象,并为每一个每个线程设置一个信号量,从而能在所有线程都结束的时候得到通知,大致的代码如下。

    FileInfo fi = new FileInfo( txtFileName.Text );

    if( fi.Exists )

    {

        btnUpload.Enabled = false;//Avoid upload twice

        //Init signals

        ManualResetEvent[] events = new ManualResetEvent[5];

        //Devide blocks

        int nTotalBytes = (int)( fi.Length / 5 );

        forint i = 0; i < 5; i++ )

        {

            events[i] = new ManualResetEvent( false );

            FileThread thdSub = new FileThread(

                i * nTotalBytes,

                ( fi.Length - i * nTotalBytes ) > nTotalBytes ? nTotalBytes:(int)( fi.Length - i * nTotalBytes ),

                fi.FullName );

            ThreadPool.QueueUserWorkItem( new WaitCallback( thdSub.UploadFile ), events[i] );

        }

        //Wait for threads finished

        WaitHandle.WaitAll( events );

        //Reset button status

        btnUpload.Enabled = true;

    }

 

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

 

本来想打包提供给大家下载,没想到CSDNBlog对于这点做的太差,老是异常。

 

如下是客户端的完整代码。

 

//--------------------------- Multi-thread Upload Demo ---------------------------------------

 

//--------------------------------------------------------------------------------------------

 

//---File:          frmUpload

 

//---Description:   The multi-thread upload form file to demenstrate howto use multi-thread to

 

//                  upload files

 

//---Author:        Knight

 

//---Date:          Oct.12, 2006

 

//--------------------------------------------------------------------------------------------

 

//---------------------------{Multi-thread Upload Demo}---------------------------------------

 

using System;

 

using System.Drawing;

 

using System.Collections;

 

using System.ComponentModel;

 

using System.Windows.Forms;

 

using System.Data;

 

namespace CSUpload

 

{

 

    using System.IO;

 

    using System.Diagnostics;

 

    using System.Threading;

 

    using WSUploadFile;//Web-service reference namespace

 

    ///<summary>

 

    /// Summary description for Form1.

 

    ///</summary>

 

    public class frmUpload : System.Windows.Forms.Form

 

    {

 

        private System.Windows.Forms.TextBox txtFileName;

 

        private System.Windows.Forms.Button btnBrowse;

 

        private System.Windows.Forms.Button btnUpload;

 

        ///<summary>

 

        /// Required designer variable.

 

        ///</summary>

 

        private System.ComponentModel.Container components = null;

 

        public frmUpload()

 

        {

 

            //

 

            // Required for Windows Form Designer support

 

            //

 

            InitializeComponent();

 

            //

 

            // TODO: Add any constructor code after InitializeComponent call

 

            //

 

        }

 

        ///<summary>

 

        /// Clean up any resources being used.

 

        ///</summary>

 

        protected override void Dispose( bool disposing )

 

        {

 

            if( disposing )

 

            {

 

                if (components != null)

 

                {

 

                    components.Dispose();

 

                }

 

            }

 

            base.Dispose( disposing );

 

        }

 

        #region Windows Form Designer generated code

 

        ///<summary>

 

        /// Required method for Designer support - do not modify

 

        /// the contents of this method with the code editor.

 

        ///</summary>

 

        private void InitializeComponent()

 

        {

 

            this.txtFileName = new System.Windows.Forms.TextBox();

 

            this.btnBrowse = new System.Windows.Forms.Button();

 

            this.btnUpload = new System.Windows.Forms.Button();

 

            this.SuspendLayout();

 

            //

 

            // txtFileName

 

            //

 

            this.txtFileName.Location = new System.Drawing.Point(16, 24);

 

            this.txtFileName.Name = "txtFileName";

 

            this.txtFileName.Size = new System.Drawing.Size(248, 20);

 

            this.txtFileName.TabIndex = 0;

 

            this.txtFileName.Text = "";

 

            //

 

            // btnBrowse

 

            //

 

            this.btnBrowse.Location = new System.Drawing.Point(272, 24);

 

            this.btnBrowse.Name = "btnBrowse";

 

            this.btnBrowse.TabIndex = 1;

 

            this.btnBrowse.Text = "&Browse...";

 

            this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click);

 

            //

 

            // btnUpload

 

            //

 

            this.btnUpload.Location = new System.Drawing.Point(272, 56);

 

            this.btnUpload.Name = "btnUpload";

 

            this.btnUpload.TabIndex = 2;

 

            this.btnUpload.Text = "&Upload";

 

            this.btnUpload.Click += new System.EventHandler(this.btnUpload_Click);

 

            //

 

            // frmUpload

 

            //

 

            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);

 

            this.ClientSize = new System.Drawing.Size(370, 111);

 

            this.Controls.Add(this.btnUpload);

 

            this.Controls.Add(this.btnBrowse);

 

            this.Controls.Add(this.txtFileName);

 

            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;

 

            this.MaximizeBox = false;

 

            this.Name = "frmUpload";

 

            this.Text = "Upload";

 

            this.Load += new System.EventHandler(this.frmUpload_Load);

 

            this.ResumeLayout(false);

 

        }

 

        #endregion

 

        ///<summary>

 

        /// The main entry point for the application.

 

        ///</summary>

 

        static void Main()

 

        {

 

            Application.Run(new frmUpload());

 

        }

 

        private FileUpload myUpload = new FileUpload();

 

        private void UploadData( string FileName, int StartPos, byte[] bData )

 

        {

 

            //Call web service upload

 

            myUpload.UploadFileData( FileName, StartPos, bData );

 

        }

 

        private void btnUpload_Click(object sender, System.EventArgs e)

 

        {

 

            FileInfo fi = new FileInfo( txtFileName.Text );

 

            if( fi.Exists )

 

            {

 

                btnUpload.Enabled = false;//Avoid upload twice

 

                //Init signals

 

                ManualResetEvent[] events = new ManualResetEvent[5];

 

                //Devide blocks

 

                int nTotalBytes = (int)( fi.Length / 5 );

 

                forint i = 0; i < 5; i++ )

 

                {

 

                    events[i] = new ManualResetEvent( false );

 

                    FileThread thdSub = new FileThread(

 

                        i * nTotalBytes,

 

                        ( fi.Length - i * nTotalBytes ) > nTotalBytes ? nTotalBytes:(int)( fi.Length - i * nTotalBytes ),

 

                        fi.FullName );

 

                    ThreadPool.QueueUserWorkItem( new WaitCallback( thdSub.UploadFile ), events[i] );

 

                }

 

                //Wait for threads finished

 

                WaitHandle.WaitAll( events );

 

                //Reset button status

 

                btnUpload.Enabled = true;

 

            }

 

       

 

        }

 

        private void frmUpload_Load(object sender, System.EventArgs e)

 

        {

 

            FileThread.UploadHandle = new UploadFileData( this.UploadData );

 

        }

 

        private void btnBrowse_Click(object sender, System.EventArgs e)

 

        {

 

            if( fileOpen.ShowDialog() == DialogResult.OK )

 

                txtFileName.Text = fileOpen.FileName;

 

        }

 

        private OpenFileDialog fileOpen = new OpenFileDialog();

 

       

 

    }

 

    public delegate void UploadFileData( string FileName, int StartPos, byte[] bData );

 

    ///<summary>

 

    /// FileThread: a class for sub-thread

 

    ///</summary>

 

    sealed class FileThread

 

    {

 

        private int nStartPos;

 

        private int nTotalBytes;

 

        private string strFileName;

 

        public static UploadFileData UploadHandle;

 

        ///<summary>

 

        /// Constructor

 

        ///</summary>

 

        ///<param name="StartPos"></param>

 

        ///<param name="TotalBytes"></param>

 

        ///<param name="FileName"></param>

 

        public FileThread( int StartPos, int TotalBytes, string FileName )

 

        {

 

            //Init thread variant

 

            nStartPos = StartPos;

 

            nTotalBytes = TotalBytes;

 

            strFileName = FileName;

 

            //Only for debug

 

            Debug.WriteLine( string.Format( "File name:{0} position: {1} total byte:{2}",

 

                strFileName, nStartPos, nTotalBytes ) );

 

        }

 

        ///<summary>

 

        /// Sub-thread entry function

 

        ///</summary>

 

        ///<param name="stateinfo"></param>

 

        public void UploadFile( object stateinfo )

 

        {

 

            int nRealRead, nBufferSize;

 

            const int BUFFER_SIZE = 10240;

 

            using( FileStream fs = new FileStream( strFileName,

 

                       FileMode.Open, FileAccess.Read,

 

                       FileShare.Read ) )

 

            {

 

                string sName = strFileName.Substring( strFileName.LastIndexOf( """" ) + 1 );

 

                byte[] bBuffer = new byte[BUFFER_SIZE];//Init 10k buffer

 

                fs.Position = nStartPos;

 

                nRealRead = 0;

 

                do

 

                {

 

                    nBufferSize = BUFFER_SIZE;

 

                    if( nRealRead + BUFFER_SIZE > nTotalBytes )

 

                        nBufferSize = nTotalBytes - nRealRead;

 

                    nBufferSize = fs.Read( bBuffer, 0, nBufferSize );

 

                    if( nBufferSize == BUFFER_SIZE )

 

                        UploadHandle( sName,

 

                            nRealRead + nStartPos,

 

                            bBuffer );

 

                    else if( nBufferSize > 0 )

 

                    {

 

                        //Copy data

 

                        byte[] bytData = new byte[nBufferSize];

 

                        Array.Copy( bBuffer,0, bytData, 0, nBufferSize );

 

                        UploadHandle( sName,

 

                            nRealRead + nStartPos,

 

                            bytData );

 

                    }

 

                    nRealRead += nBufferSize;

 

                }

 

                while( nRealRead < nTotalBytes );

 

            }

 

            //Release signal

 

            ManualResetEvent mr = stateinfo as ManualResetEvent;

 

            if( mr != null )

 

                mr.Set();

 

        }

 

    }

 

}

 

posted @ 2012-03-12 17:00  郑文亮  阅读(512)  评论(0编辑  收藏  举报