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

在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 );

        for( int 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 );

                for( int 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 on 2008-04-22 13:49  谭洪星  阅读(681)  评论(0编辑  收藏  举报

导航