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

    技术2022-06-22  67

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

     

        ///

        /// FileThread: a class for sub-thread

        ///

        sealed class FileThread

        {

            private int nStartPos;

            private int nTotalBytes;

            private string strFileName;

            public static UploadFileData UploadHandle;

     

            ///

            /// Constructor

            ///

            ///

            ///

            ///

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

            }

     

            ///

            /// Sub-thread entry function

            ///

            ///

            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,

                    &nbs, p;( 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;

        }

     

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

     

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

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

    //--------------------------- 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 description for Form1.

        ///

        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;

            ///

            /// Required designer variable.

            ///

            private System.ComponentModel.Container components = null;

     

            public frmUpload()

            {

                //

                // Required for Windows Form Designer support

                //

                InitializeComponent();

     

                //

                // TODO: Add any constructor code after InitializeComponent call

                //

            }

     

            ///

            /// Clean up any resources being used.

            ///

            protected override void Dispose( bool disposing )

            {

                if( disposing )

                {

                    if (components != null)

                    {

                        components.Dispose();

                    }

                }

                base.Dispose( disposing );

            }

     

            #region Windows Form Designer generated code

            ///

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

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

            ///

            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

     

            ///

            /// The main entry point for the application.

            ///

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

     

        ///

        /// FileThread: a class for sub-thread

        ///

        sealed class FileThread

        {

            private int nStartPos;

            private int nTotalBytes;

            private string strFileName;

            public static UploadFileData UploadHandle;

     

            ///

            /// Constructor

            ///

            ///

            ///

            ///

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

            }

     

            ///

            /// Sub-thread entry function

            ///

            ///

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

            }

        }

     

    }

     

     


    最新回复(0)