在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;
}
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();
}
}
/**/ ///
/// 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,
( 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;
}
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 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 );
}
Windows Form Designer generated code#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);
//
// bt
nUpload
//
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.Enable
d = 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 UploadFil
eData 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();
}
}
}
// --------------------------------------------------------------------------------------------
// ---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 );
}
Windows Form Designer generated code#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);
//
// bt
nUpload
//
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.Enable
d = 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 UploadFil
eData 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();
}
}
}