天天看點

FTP上傳類FTP上傳類

using system;

using system.collections.generic;

using system.text;

using system.net;

using system.io;

using system.globalization;

using system.text.regularexpressions;

namespace webbaselib

{

/// <summary>

/// ftp處理操作類

/// 功能:

/// 下載下傳檔案

/// 上傳檔案

/// 上傳檔案的進度資訊

/// 下載下傳檔案的進度資訊

/// 删除檔案

/// 列出檔案

/// 列出目錄

/// 進入子目錄

/// 退出目前目錄傳回上一層目錄

/// 判斷遠端檔案是否存在

/// 删除遠端檔案

/// 建立目錄

/// 删除目錄

/// 檔案(目錄)改名

/// </summary>

/// <remarks>

/// 建立人:南瘋

/// 建立時間:2007年4月28日

/// </remarks>

#region 檔案資訊結構

public struct filestruct

public string flags;

public string owner;

public string group;

public bool isdirectory;

public datetime createtime;

public string name;

}

public enum fileliststyle

unixstyle,

windowsstyle,

unknown

#endregion

public class newftp

#region 屬性資訊

/// ftp請求對象

ftpwebrequest request = null;

/// ftp響應對象

ftpwebresponse response = null;

/// ftp伺服器位址

private uri _uri;

public uri uri

get

if( _directorypath == "/" )

return _uri;

else

string struri = _uri.tostring();

if( struri.endswith( "/" ) )

struri = struri.substring( 0, struri.length - 1 );

return new uri( struri + this.directorypath );

set

if( value.scheme != uri.urischemeftp )

throw new exception( "ftp 位址格式錯誤!" );

_uri = new uri( value.getleftpart( uripartial.authority ) );

_directorypath = value.absolutepath;

if( !_directorypath.endswith( "/" ) )

_directorypath += "/";

/// 目前工作目錄

private string _directorypath;

public string directorypath

return _directorypath;

_directorypath = value;

/// ftp登入使用者

private string _username;

public string username

return _username;

_username = value;

/// 錯誤資訊

private string _errormsg;

public string errormsg

return _errormsg;

_errormsg = value;

/// ftp登入密碼

private string _password;

public string password

return _password;

_password = value;

/// 連接配接ftp伺服器的代理服務

private webproxy _proxy = null;

public webproxy proxy

return _proxy;

_proxy = value;

/// 是否需要删除臨時檔案

private bool _isdeletetempfile = false;

/// 異步上傳所臨時生成的檔案

private string _uploadtempfile = "";

#region 事件

public delegate void de_downloadprogresschanged( object sender, downloadprogresschangedeventargs e );

public delegate void de_downloaddatacompleted( object sender, system.componentmodel.asynccompletedeventargs e );

public delegate void de_uploadprogresschanged( object sender, uploadprogresschangedeventargs e );

public delegate void de_uploadfilecompleted( object sender, uploadfilecompletedeventargs e );

/// 異步下載下傳進度發生改變觸發的事件

public event de_downloadprogresschanged downloadprogresschanged;

/// 異步下載下傳檔案完成之後觸發的事件

public event de_downloaddatacompleted downloaddatacompleted;

/// 異步上傳進度發生改變觸發的事件

public event de_uploadprogresschanged uploadprogresschanged;

/// 異步上傳檔案完成之後觸發的事件

public event de_uploadfilecompleted uploadfilecompleted;

#region 構造析構函數

/// 構造函數

/// <param name="ftpuri">ftp位址</param>

/// <param name="strusername">登入使用者名</param>

/// <param name="strpassword">登入密碼</param>

public newftp( uri ftpuri, string strusername, string strpassword )

this._uri = new uri( ftpuri.getleftpart( uripartial.authority ) );

_directorypath = ftpuri.absolutepath;

this._username = strusername;

this._password = strpassword;

this._proxy = null;

/// <param name="objproxy">連接配接代理</param>

public newftp( uri ftpuri, string strusername, string strpassword, webproxy objproxy )

this._proxy = objproxy;

public newftp()

this._username = "anonymous"; //匿名使用者

this._password = "@anonymous";

this._uri = null;

/// 析構函數

~newftp()

if( response != null )

response.close();

response = null;

if( request != null )

request.abort();

request = null;

#region 建立連接配接

/// 建立ftp連結,傳回響應對象

/// <param name="uri">ftp位址</param>

/// <param name="ftpmathod">操作指令</param>

private ftpwebresponse open( uri uri, string ftpmathod )

try

request = ( ftpwebrequest ) webrequest.create( uri );

request.method = ftpmathod;

request.usebinary = true;

request.credentials = new networkcredential( this.username, this.password );

if( this.proxy != null )

request.proxy = this.proxy;

return ( ftpwebresponse ) request.getresponse();

catch( exception ep )

errormsg = ep.tostring();

throw ep;

/// 建立ftp連結,傳回請求對象

private ftpwebrequest openrequest( uri uri, string ftpmathod )

return request;

#region 下載下傳檔案

/// 從ftp伺服器下載下傳檔案,使用與遠端檔案同名的檔案名來儲存檔案

/// <param name="remotefilename">遠端檔案名</param>

/// <param name="localpath">本地路徑</param>

public bool downloadfile( string remotefilename, string localpath )

return downloadfile( remotefilename, localpath, remotefilename );

/// 從ftp伺服器下載下傳檔案,指定本地路徑和本地檔案名

/// <param name="localfilepath">儲存檔案的本地路徑,後面帶有""</param>

/// <param name="localfilename">儲存本地的檔案名</param>

public bool downloadfile( string remotefilename, string localpath, string localfilename )

byte[] bt = null;

if( !isvalidfilechars( remotefilename ) || !isvalidfilechars( localfilename ) || !isvalidpathchars( localpath ) )

throw new exception( "非法檔案名或目錄名!" );

if( !directory.exists( localpath ) )

throw new exception( "本地檔案路徑不存在!" );

string localfullpath = path.combine( localpath, localfilename );

if( file.exists( localfullpath ) )

throw new exception( "目前路徑下已經存在同名檔案!" );

bt = downloadfile( remotefilename );

if( bt != null )

filestream stream = new filestream( localfullpath, filemode.create );

stream.write( bt, 0, bt.length );

stream.flush();

stream.close();

return true;

return false;

/// 從ftp伺服器下載下傳檔案,傳回檔案二進制資料

public byte[] downloadfile( string remotefilename )

if( !isvalidfilechars( remotefilename ) )

response = open( new uri( this.uri.tostring() + remotefilename ), webrequestmethods.ftp.downloadfile );

stream reader = response.getresponsestream();

memorystream mem = new memorystream( 1024 * 500 );

byte[] buffer = new byte[ 1024 ];

int bytesread = 0;

int totalbyteread = 0;

while( true )

bytesread = reader.read( buffer, 0, buffer.length );

totalbyteread += bytesread;

if( bytesread == 0 )

break;

mem.write( buffer, 0, bytesread );

if( mem.length > 0 )

return mem.toarray();

return null;

#region 異步下載下傳檔案

/// 從ftp伺服器異步下載下傳檔案,指定本地路徑和本地檔案名

/// <param name="localpath">儲存檔案的本地路徑,後面帶有""</param>

public void downloadfileasync( string remotefilename, string localpath, string localfilename )

downloadfileasync( remotefilename, localfullpath );

/// 從ftp伺服器異步下載下傳檔案,指定本地完整路徑檔案名

/// <param name="localfullpath">本地完整路徑檔案名</param>

public void downloadfileasync( string remotefilename, string localfullpath )

mywebclient client = new mywebclient();

client.downloadprogresschanged += new downloadprogresschangedeventhandler( client_downloadprogresschanged );

client.downloadfilecompleted += new system.componentmodel.asynccompletedeventhandler( client_downloadfilecompleted );

client.credentials = new networkcredential( this.username, this.password );

client.proxy = this.proxy;

client.downloadfileasync( new uri( this.uri.tostring() + remotefilename ), localfullpath );

/// <param name="sender">下載下傳對象</param>

/// <param name="e">資料資訊對象</param>

void client_downloadfilecompleted( object sender, system.componentmodel.asynccompletedeventargs e )

if( downloaddatacompleted != null )

downloaddatacompleted( sender, e );

/// <param name="e">進度資訊對象</param>

void client_downloadprogresschanged( object sender, downloadprogresschangedeventargs e )

if( downloadprogresschanged != null )

downloadprogresschanged( sender, e );

#region 上傳檔案

/// 上傳檔案到ftp伺服器

/// <param name="localfullpath">本地帶有完整路徑的檔案名</param>

public bool uploadfile( string localfullpath )

return uploadfile( localfullpath, path.getfilename( localfullpath ), false );

/// <param name="localfullpath">本地帶有完整路徑的檔案</param>

/// <param name="overwriteremotefile">是否覆寫遠端伺服器上面同名的檔案</param>

public bool uploadfile( string localfullpath, bool overwriteremotefile )

return uploadfile( localfullpath, path.getfilename( localfullpath ), overwriteremotefile );

/// <param name="remotefilename">要在ftp伺服器上面儲存檔案名</param>

public bool uploadfile( string localfullpath, string remotefilename )

return uploadfile( localfullpath, remotefilename, false );

public bool uploadfile( string localfullpath, string remotefilename, bool overwriteremotefile )

if( !isvalidfilechars( remotefilename ) || !isvalidfilechars( path.getfilename( localfullpath ) ) || !isvalidpathchars( path.getdirectoryname( localfullpath ) ) )

filestream stream = new filestream( localfullpath, filemode.open, fileaccess.read );

byte[] bt = new byte[ stream.length ];

stream.read( bt, 0, ( int32 ) stream.length ); //注意,因為int32的最大限制,最大上傳檔案隻能是大約2g多一點

return uploadfile( bt, remotefilename, overwriteremotefile );

throw new exception( "本地檔案不存在!" );

/// <param name="filebytes">上傳的二進制資料</param>

public bool uploadfile( byte[] filebytes, string remotefilename )

return uploadfile( filebytes, remotefilename, false );

/// <param name="filebytes">檔案二進制内容</param>

public bool uploadfile( byte[] filebytes, string remotefilename, bool overwriteremotefile )

throw new exception( "非法檔案名!" );

if( !overwriteremotefile && fileexist( remotefilename ) )

throw new exception( "ftp服務上面已經存在同名檔案!" );

response = open( new uri( this.uri.tostring() + remotefilename ), webrequestmethods.ftp.uploadfile );

stream requeststream = request.getrequeststream();

memorystream mem = new memorystream( filebytes );

int totalread = 0;

bytesread = mem.read( buffer, 0, buffer.length );

totalread += bytesread;

requeststream.write( buffer, 0, bytesread );

requeststream.close();

response = ( ftpwebresponse ) request.getresponse();

mem.close();

mem.dispose();

filebytes = null;

#region 異步上傳檔案

/// 異步上傳檔案到ftp伺服器

public void uploadfileasync( string localfullpath )

uploadfileasync( localfullpath, path.getfilename( localfullpath ), false );

public void uploadfileasync( string localfullpath, bool overwriteremotefile )

uploadfileasync( localfullpath, path.getfilename( localfullpath ), overwriteremotefile );

public void uploadfileasync( string localfullpath, string remotefilename )

uploadfileasync( localfullpath, remotefilename, false );

public void uploadfileasync( string localfullpath, string remotefilename, bool overwriteremotefile )

client.uploadprogresschanged += new uploadprogresschangedeventhandler( client_uploadprogresschanged );

client.uploadfilecompleted += new uploadfilecompletedeventhandler( client_uploadfilecompleted );

client.uploadfileasync( new uri( this.uri.tostring() + remotefilename ), localfullpath );

public void uploadfileasync( byte[] filebytes, string remotefilename )

uploadfileasync( filebytes, remotefilename, false );

public void uploadfileasync( byte[] filebytes, string remotefilename, bool overwriteremotefile )

string temppath = system.environment.getfolderpath( environment.specialfolder.templates );

if( !temppath.endswith( "/" ) )

temppath += "/";

string tempfile = temppath + path.getrandomfilename();

tempfile = path.changeextension( tempfile, path.getextension( remotefilename ) );

filestream stream = new filestream( tempfile, filemode.createnew, fileaccess.write );

stream.write( filebytes, 0, filebytes.length ); //注意,因為int32的最大限制,最大上傳檔案隻能是大約2g多一點

stream.dispose();

_isdeletetempfile = true;

_uploadtempfile = tempfile;

uploadfileasync( tempfile, remotefilename, overwriteremotefile );

void client_uploadfilecompleted( object sender, uploadfilecompletedeventargs e )

if( _isdeletetempfile )

if( file.exists( _uploadtempfile ) )

file.setattributes( _uploadtempfile, fileattributes.normal );

file.delete( _uploadtempfile );

_isdeletetempfile = false;

if( uploadfilecompleted != null )

uploadfilecompleted( sender, e );

void client_uploadprogresschanged( object sender, uploadprogresschangedeventargs e )

if( uploadprogresschanged != null )

uploadprogresschanged( sender, e );

#region 列出目錄檔案資訊

/// 列出ftp伺服器上面目前目錄的所有檔案和目錄

public filestruct[] listfilesanddirectories()

response = open( this.uri, webrequestmethods.ftp.listdirectorydetails );

streamreader stream = new streamreader( response.getresponsestream(), encoding.default );

string datastring = stream.readtoend();

filestruct[] list = getlist( datastring );

return list;

/// 列出ftp伺服器上面目前目錄的所有檔案

public filestruct[] listfiles()

filestruct[] listall = listfilesanddirectories();

list<filestruct> listfile = new list<filestruct>();

foreach( filestruct file in listall )

if( !file.isdirectory )

listfile.add( file );

return listfile.toarray();

/// 列出ftp伺服器上面目前目錄的所有的目錄

public filestruct[] listdirectories()

list<filestruct> listdirectory = new list<filestruct>();

if( file.isdirectory )

listdirectory.add( file );

return listdirectory.toarray();

/// 獲得檔案和目錄清單

/// <param name="datastring">ftp傳回的清單字元資訊</param>

private filestruct[] getlist( string datastring )

list<filestruct> mylistarray = new list<filestruct>();

string[] datarecords = datastring.split( '

' );

fileliststyle _directoryliststyle = guessfileliststyle( datarecords );

foreach( string s in datarecords )

if( _directoryliststyle != fileliststyle.unknown && s != "" )

filestruct f = new filestruct();

f.name = "..";

switch( _directoryliststyle )

case fileliststyle.unixstyle:

f = parsefilestructfromunixstylerecord( s );

case fileliststyle.windowsstyle:

f = parsefilestructfromwindowsstylerecord( s );

if( !( f.name == "." || f.name == ".." ) )

mylistarray.add( f );

return mylistarray.toarray();

/// 從windows格式中傳回檔案資訊

/// <param name="record">檔案資訊</param>

private filestruct parsefilestructfromwindowsstylerecord( string record )

string processstr = record.trim();

string datestr = processstr.substring( 0, 8 );

processstr = ( processstr.substring( 8, processstr.length - 8 ) ).trim();

string timestr = processstr.substring( 0, 7 );

processstr = ( processstr.substring( 7, processstr.length - 7 ) ).trim();

datetimeformatinfo mydtfi = new cultureinfo( "en-us", false ).datetimeformat;

mydtfi.shorttimepattern = "t";

f.createtime = datetime.parse( datestr + " " + timestr, mydtfi );

if( processstr.substring( 0, 5 ) == "<dir>" )

f.isdirectory = true;

processstr = ( processstr.substring( 5, processstr.length - 5 ) ).trim();

string[] strs = processstr.split( new char[] { ' ' }, stringsplitoptions.removeemptyentries ); // true);

processstr = strs[ 1 ];

f.isdirectory = false;

f.name = processstr;

return f;

/// 判斷檔案清單的方式window方式還是unix方式

/// <param name="recordlist">檔案資訊清單</param>

private fileliststyle guessfileliststyle( string[] recordlist )

foreach( string s in recordlist )

if( s.length > 10

&& regex.ismatch( s.substring( 0, 10 ), "(-|d)(-|r)(-|w)(-|x)(-|r)(-|w)(-|x)(-|r)(-|w)(-|x)" ) )

return fileliststyle.unixstyle;

else if( s.length > 8

&& regex.ismatch( s.substring( 0, 8 ), "[0-9][0-9]-[0-9][0-9]-[0-9][0-9]" ) )

return fileliststyle.windowsstyle;

return fileliststyle.unknown;

/// 從unix格式中傳回檔案資訊

private filestruct parsefilestructfromunixstylerecord( string record )

f.flags = processstr.substring( 0, 10 );

f.isdirectory = ( f.flags[ 0 ] == 'd' );

processstr = ( processstr.substring( 11 ) ).trim();

_cutsubstringfromstringwithtrim( ref processstr, ' ', 0 ); //跳過一部分

f.owner = _cutsubstringfromstringwithtrim( ref processstr, ' ', 0 );

f.group = _cutsubstringfromstringwithtrim( ref processstr, ' ', 0 );

string yearortime = processstr.split( new char[] { ' ' }, stringsplitoptions.removeemptyentries )[ 2 ];

if( yearortime.indexof( ":" ) >= 0 ) //time

processstr = processstr.replace( yearortime, datetime.now.year.tostring() );

f.createtime = datetime.parse( _cutsubstringfromstringwithtrim( ref processstr, ' ', 8 ) );

f.name = processstr; //最後就是名稱

/// 按照一定的規則進行字元串截取

/// <param name="s">截取的字元串</param>

/// <param name="c">查找的字元</param>

/// <param name="startindex">查找的位置</param>

private string _cutsubstringfromstringwithtrim( ref string s, char c, int startindex )

int pos1 = s.indexof( c, startindex );

string retstring = s.substring( 0, pos1 );

s = ( s.substring( pos1 ) ).trim();

return retstring;

#region 目錄或檔案存在的判斷

/// 判斷目前目錄下指定的子目錄是否存在

/// <param name="remotedirectoryname">指定的目錄名</param>

public bool directoryexist( string remotedirectoryname )

if( !isvalidpathchars( remotedirectoryname ) )

throw new exception( "目錄名非法!" );

filestruct[] listdir = listdirectories();

foreach( filestruct dir in listdir )

if( dir.name == remotedirectoryname )

/// 判斷一個遠端檔案是否存在伺服器目前目錄下面

public bool fileexist( string remotefilename )

throw new exception( "檔案名非法!" );

filestruct[] listfile = listfiles();

foreach( filestruct file in listfile )

if( file.name == remotefilename )

#region 删除檔案

/// 從ftp伺服器上面删除一個檔案

public void deletefile( string remotefilename )

response = open( new uri( this.uri.tostring() + remotefilename ), webrequestmethods.ftp.deletefile );

#region 重命名檔案

/// 更改一個檔案的名稱或一個目錄的名稱

/// <param name="remotefilename">原始檔案或目錄名稱</param>

/// <param name="newfilename">新的檔案或目錄的名稱</param>

public bool rename( string remotefilename, string newfilename )

if( !isvalidfilechars( remotefilename ) || !isvalidfilechars( newfilename ) )

if( remotefilename == newfilename )

if( fileexist( remotefilename ) )

request = openrequest( new uri( this.uri.tostring() + remotefilename ), webrequestmethods.ftp.rename );

request.renameto = newfilename;

throw new exception( "檔案在伺服器上不存在!" );

#region 拷貝、移動檔案

/// 把目前目錄下面的一個檔案拷貝到伺服器上面另外的目錄中,注意,拷貝檔案之後,目前工作目錄還是檔案原來所在的目錄

/// <param name="remotefile">目前目錄下的檔案名</param>

/// <param name="directoryname">新目錄名稱。

/// 說明:如果新目錄是目前目錄的子目錄,則直接指定子目錄。如: subdirectory1/subdirectory2 ;

/// 如果新目錄不是目前目錄的子目錄,則必須從根目錄一級一級的指定。如: ./newdirectory/subdirectory1/subdirectory2

/// </param>

/// <returns></returns>

public bool copyfiletoanotherdirectory( string remotefile, string directoryname )

string currentworkdir = this.directorypath;

byte[] bt = downloadfile( remotefile );

gotodirectory( directoryname );

bool success = uploadfile( bt, remotefile, false );

this.directorypath = currentworkdir;

return success;

/// 把目前目錄下面的一個檔案移動到伺服器上面另外的目錄中,注意,移動檔案之後,目前工作目錄還是檔案原來所在的目錄

public bool movefiletoanotherdirectory( string remotefile, string directoryname )

if( directoryname == "" )

if( !directoryname.startswith( "/" ) )

directoryname = "/" + directoryname;

if( !directoryname.endswith( "/" ) )

directoryname += "/";

bool success = rename( remotefile, directoryname + remotefile );

#region 建立、删除子目錄

/// 在ftp伺服器上目前工作目錄建立一個子目錄

/// <param name="directoryname">子目錄名稱</param>

public bool makedirectory( string directoryname )

if( !isvalidpathchars( directoryname ) )

if( directoryexist( directoryname ) )

throw new exception( "伺服器上面已經存在同名的檔案名或目錄名!" );

string a = this.uri.tostring();

string b = directoryname;

response = open( new uri( this.uri.tostring() + directoryname ), webrequestmethods.ftp.makedirectory );

/// 從目前工作目錄中删除一個子目錄

public bool removedirectory( string directoryname )

if( !directoryexist( directoryname ) )

throw new exception( "伺服器上面不存在指定的檔案名或目錄名!" );

response = open( new uri( this.uri.tostring() + directoryname ), webrequestmethods.ftp.removedirectory );

#region 檔案、目錄名稱有效性判斷

/// 判斷目錄名中字元是否合法

/// <param name="directoryname">目錄名稱</param>

public bool isvalidpathchars( string directoryname )

char[] invalidpathchars = path.getinvalidpathchars();

char[] dirchar = directoryname.tochararray();

foreach( char c in dirchar )

if( array.binarysearch( invalidpathchars, c ) >= 0 )

/// 判斷檔案名中字元是否合法

/// <param name="filename">檔案名稱</param>

public bool isvalidfilechars( string filename )

char[] invalidfilechars = path.getinvalidfilenamechars();

char[] namechar = filename.tochararray();

foreach( char c in namechar )

if( array.binarysearch( invalidfilechars, c ) >= 0 )

#region 目錄切換操作

/// 進入一個目錄

/// <param name="directoryname">

/// 新目錄的名字。

public bool gotodirectory( string directoryname )

string currentworkpath = this.directorypath;

directoryname = directoryname.replace( "/", "/" );

string[] directorynames = directoryname.split( new char[] { '/' } );

if( directorynames[ 0 ] == "." )

this.directorypath = "/";

if( directorynames.length == 1 )

array.clear( directorynames, 0, 1 );

bool success = false;

foreach( string dir in directorynames )

if( dir != null )

success = enteronesubdirectory( dir );

if( !success )

this.directorypath = currentworkpath;

/// 從目前工作目錄進入一個子目錄

private bool enteronesubdirectory( string directoryname )

if( directoryname.indexof( "/" ) >= 0 || !isvalidpathchars( directoryname ) )

throw new exception( "目錄名非法!" );

if( directoryname.length > 0 && directoryexist( directoryname ) )

_directorypath += directoryname;

/// 從目前工作目錄往上一級目錄

public bool comeoutdirectory()

errormsg = "目前目錄已經是根目錄!";

throw new exception( "目前目錄已經是根目錄!" );

char[] sp = new char[ 1 ] { '/' };

string[] strdir = _directorypath.split( sp, stringsplitoptions.removeemptyentries );

if( strdir.length == 1 )

_directorypath = "/";

_directorypath = string.join( "/", strdir, 0, strdir.length - 1 );

#region 重載webclient,支援ftp進度

internal class mywebclient : webclient

protected override webrequest getwebrequest( uri address )

ftpwebrequest req = ( ftpwebrequest ) base.getwebrequest( address );

req.usepassive = false;

return req;

繼續閱讀