现在的位置: 首页 > 综合 > 正文

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

2013年04月08日 ⁄ 综合 ⁄ 共 12283字 ⁄ 字号 评论关闭
在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;
    }
 
总体来说,程序还是相对比较简单,而我也只是做了个简单例子而已,一些细节都没有进行处理。
 
本来想打包提供给大家下载,没想到CSDN的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>
    /// 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();
        }
    }
 
}
 

 

抱歉!评论已关闭.