前几天,看见园子里面的博友写了一个支持断点续传的FTP类,一时技痒,干脆写了个更完整的clsFtp类。只是我写这个clsFtp不是支持断点续传的目的,而是为了封装FTP几个基本常用的操作接口。
功能
公共构造函数
名称 | 说明 |
clsFTP() | 初始化clsFtp类的新实例 |
clsFTP(Uri FtpUri, string strUserName, string strPassword) | 由FTP地址、FTP登录用户信息、FTP登录用户密码初始化clsFtp类的新实例 |
clsFTP(Uri FtpUri, string strUserName, string strPassword, WebProxy objProxy) | 由FTP地址、FTP登录用户信息、FTP登录用户密码、代理服务器对象初始化clsFtp类的新实例 |
公共属性
名称 | 说明 |
Uri | 获取或设置FTP服务器地址 |
DirectoryPath | 获取当前工作目录 |
UserName | 获取或设置FTP登录用户 |
Password | 获取或设置FTP登录密码 |
Proxy | 获取或设置连接FTP服务器的代理服务 |
ErrorMsg | 获取操在返回的错误信息 |
公共方法
名称 | 说明 |
DownloadFile(string RemoteFileName, string LocalPath) | 从FTP服务器下载文件,使用与远程文件同名的文件名来保存文件。 参数说明: RemoteFileName: 远程文件名 LocalPath: 本地路径 |
DownloadFile(string RemoteFileName, string LocalPath, string LocalFileName) | 从FTP服务器下载文件,指定本地路径和本地文件名。 参数说明: LocalPath: 本地路径 LocalFilePath: 保存文件的本地路径,后面带有"\" LocalFileName: 保存本地的文件名 |
DownloadFile(string RemoteFileName) | 从FTP服务器下载文件,返回文件二进制数据。 参数说明: RemoteFileName: 远程文件名 |
DownloadFileAsync(string RemoteFileName, string LocalPath, string LocalFileName) | 从FTP服务器异步下载文件,指定本地路径和本地文件名。 参数说明: RemoteFileName: 远程文件名 LocalPath: 保存文件的本地路径,后面带有"\" LocalFileName: 保存本地的文件名 |
DownloadFileAsync(string RemoteFileName, string LocalFullPath) | 从FTP服务器异步下载文件,指定本地完整路径文件名。 参数说明: RemoteFileName: 远程文件名 LocalFullPath: 本地完整路径文件名 |
UploadFile(string LocalFullPath) | 上传文件到FTP服务器。 参数说明: LocalFullPath: 本地带有完整路径的文件名 |
UploadFile(string LocalFullPath, bool OverWriteRemoteFile) | 上传文件到FTP服务器。 参数说明: LocalFullPath: 本地带有完整路径的文件 OverWriteRemoteFile: 是否覆盖远程服务器上面同名的文件 |
UploadFile(string LocalFullPath, string RemoteFileName) | 上传文件到FTP服务器。 参数说明: LocalFullPath: 本地带有完整路径的文件 RemoteFileName: 要在FTP服务器上面保存文件名 |
UploadFile(string LocalFullPath, string RemoteFileName, bool OverWriteRemoteFile) | 上传文件到FTP服务器。 参数说明: LocalFullPath: 本地带有完整路径的文件名 RemoteFileName: 要在FTP服务器上面保存文件名 OverWriteRemoteFile: 是否覆盖远程服务器上面同名的文件 |
UploadFile(byte[] FileBytes, string RemoteFileName) | 上传文件到FTP服务器。 参数说明: FileBytes: 上传的二进制数据 RemoteFileName: 要在FTP服务器上面保存文件名 |
UploadFile(byte[] FileBytes, string RemoteFileName, bool OverWriteRemoteFile) | 上传文件到FTP服务器。 参数说明: FileBytes: 文件二进制内容 RemoteFileName: 要在FTP服务器上面保存文件名 OverWriteRemoteFile: 是否覆盖远程服务器上面同名的文件 |
UploadFileAsync(string LocalFullPath) | 异步上传文件到FTP服务器。 参数说明: LocalFullPath: 本地带有完整路径的文件名 |
UploadFileAsync(string LocalFullPath, bool OverWriteRemoteFile) | 异步上传文件到FTP服务器。 参数说明: LocalFullPath: 本地带有完整路径的文件 OverWriteRemoteFile: 是否覆盖远程服务器上面同名的文件 |
UploadFileAsync(string LocalFullPath, string RemoteFileName) | 异步上传文件到FTP服务器。 参数说明: LocalFullPath: 本地带有完整路径的文件 RemoteFileName: 要在FTP服务器上面保存文件名 |
UploadFileAsync(string LocalFullPath, string RemoteFileName, bool OverWriteRemoteFile) | 异步上传文件到FTP服务器。 参数说明: LocalFullPath: 本地带有完整路径的文件名 RemoteFileName: 要在FTP服务器上面保存文件名 OverWriteRemoteFile: 是否覆盖远程服务器上面同名的文件 |
UploadFileAsync(byte[] FileBytes, string RemoteFileName) | 异步上传文件到FTP服务器。 参数说明: FileBytes: 上传的二进制数据 RemoteFileName: 要在FTP服务器上面保存文件名 |
UploadFileAsync(byte[] FileBytes, string RemoteFileName, bool OverWriteRemoteFile) | 异步上传文件到FTP服务器。 参数说明: FileBytes: 文件二进制内容 RemoteFileName: 要在FTP服务器上面保存文件名 OverWriteRemoteFile: 是否覆盖远程服务器上面同名的文件 |
ListFilesAndDirectories() | 列出FTP服务器上面当前目录的所有文件和目录。 |
ListFiles() | 列出FTP服务器上面当前目录的所有文件。 |
ListDirectories() | 列出FTP服务器上面当前目录的所有的目录。 |
DirectoryExist(string RemoteDirectoryName) | 判断当前目录下指定的子目录是否存在。 参数说明: RemoteDirectoryName: 指定的目录名 |
FileExist(string RemoteFileName) | 判断一个远程文件是否存在服务器当前目录下面。 参数说明: RemoteFileName: 远程文件名 |
DeleteFile(string RemoteFileName) | 从FTP服务器上面删除一个文件。 参数说明: RemoteFileName: 远程文件名 |
ReName(string RemoteFileName, string NewFileName) | 更改一个文件的名称或一个目录的名称。 参数说明: RemoteFileName: 原始文件或目录名称 NewFileName: 新的文件或目录的名称 |
CopyFileToAnotherDirectory(string RemoteFile, string DirectoryName) | 把当前目录下面的一个文件拷贝到服务器上面另外的目录中,注意,拷贝文件之后,当前工作目录还是文件原来所在的目录。 参数说明: RemoteFile: 当前目录下的文件名 DirectoryName: 新目录名称。 说明:如果新目录是当前目录的子目录,则直接指定子目录。如: SubDirectory1/SubDirectory2 ; 如果新目录不是当前目录的子目录,则必须从根目录一级一级的指定。如:./NewDirectory/SubDirectory1/SubDirectory2 |
MoveFileToAnotherDirectory(string RemoteFile, string DirectoryName) | 把当前目录下面的一个文件移动到服务器上面另外的目录中,注意,移动文件之后,当前工作目录还是文件原来所在的目录。 参数说明: RemoteFile: 当前目录下的文件名 DirectoryName: 新目录名称。 说明:如果新目录是当前目录的子目录,则直接指定子目录。如: SubDirectory1/SubDirectory2 ; 如果新目录不是当前目录的子目录,则必须从根目录一级一级的指定。如:./NewDirectory/SubDirectory1/SubDirectory2 |
MakeDirectory(string DirectoryName) | 在FTP服务器上当前工作目录建立一个子目录。 参数说明: DirectoryName: 子目录名称 |
RemoveDirectory(string DirectoryName) | 从当前工作目录中删除一个子目录。 参数说明: DirectoryName: 子目录名称 |
IsValidPathChars(string DirectoryName) | 判断目录名中字符是否合法。 参数说明: DirectoryName: 目录名称 |
IsValidFileChars(string FileName) | 判断文件名中字符是否合法。 参数说明: FileName: 文件名称 |
GotoDirectory(string DirectoryName) | 进入一个目录。 参数说明: DirectoryName: 新目录的名字。 说明:如果新目录是当前目录的子目录,则直接指定子目录。如: SubDirectory1/SubDirectory2 ; 如果新目录不是当前目录的子目录,则必须从根目录一级一级的指定。如:./NewDirectory/SubDirectory1/SubDirectory2 |
EnterOneSubDirectory(string DirectoryName) | 从当前工作目录进入一个子目录。 参数说明: DirectoryName: 子目录名称 |
ComeoutDirectory() | 从当前工作目录往上一级目录。 |
公共事件
名称 | 说明 |
DownloadProgressChanged | 异步下载进度发生改变触发的事件 |
DownloadDataCompleted | 异步下载文件完成之后触发的事件 |
UploadProgressChanged | 异步上传进度发生改变触发的事件 |
UploadFileCompleted | 异步上传文件完成之后触发的事件 |
其他说明
序号 | 说明 |
1 | 支持代理服务器。 可以显式地给Proxy属性赋值;也可以在构造函数中传递Proxy对象。如果代理需要登录用户和密码,则设置Proxy的Credentials属性,例如: Proxy.Credentials = new NetworkCredential(UserName, Password) 如果没有代理,则无需给Proxy属性赋值或者在构造函数中无需传递Proxy参数。 |
2 | 下载文件和上传文件大小最大受Int32.MaxValue限制,所以最大处理只能是2,147,483,647字节。如果您想处理更大的文件,请自己修改代码中对文件打开和读写操作部分的代码使其适应您的要求。 |
3 | 只有在异步上传文件或者异步下载文件的时候,才支持进度百分比触发事件和下载(上传)完成事件。 |
4 | 由于服务器未发送文件大小,因此被动 FTP 文件传输总是将进度百分比显示为零。若要显示进度,可以通过重写 GetWebRequest 虚拟方法来将 FTP 连接更改为活动状态。所以,我们在clsFTP类中另外使用内部类MyWebClient |
5 | 在列出文件和目录的时候,clsFTP类区分出了所获得的响应数据哪些是文件,哪些是目录。同时,考虑到了FTP服务器上面目录样式为MS DOS和UNIX两种表现形式的不同。 |
6 | 支持在FTP服务器上面不同目录之间移动文件和拷贝文件的功能。移动文件的方法比较巧妙,只是拷贝文件所使用的方法不太理想。 |
using System; using System.Collections.Generic; using System.Text; using System.Net; using System.IO; using System.Globalization; using System.Text.RegularExpressions; namespace System.Net.Ftp { /// <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 clsFTP { #region 属性信息 /// <summary> /// FTP请求对象 /// </summary> FtpWebRequest Request = null; /// <summary> /// FTP响应对象 /// </summary> FtpWebResponse Response = null; /// <summary> /// FTP服务器地址 /// </summary> private Uri _Uri; /// <summary> /// FTP服务器地址 /// </summary> 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 += "/"; } } } /// <summary> /// 当前工作目录 /// </summary> private string _DirectoryPath; /// <summary> /// 当前工作目录 /// </summary> public string DirectoryPath { get { return _DirectoryPath; } set { _DirectoryPath = value; } } /// <summary> /// FTP登录用户 /// </summary> private string _UserName; /// <summary> /// FTP登录用户 /// </summary> public string UserName { get { return _UserName; } set { _UserName = value; } } /// <summary> /// 错误信息 /// </summary> private string _ErrorMsg; /// <summary> /// 错误信息 /// </summary> public string ErrorMsg { get { return _ErrorMsg; } set { _ErrorMsg = value; } } /// <summary> /// FTP登录密码 /// </summary> private string _Password; /// <summary> /// FTP登录密码 /// </summary> public string Password { get { return _Password; } set { _Password = value; } } /// <summary> /// 连接FTP服务器的代理服务 /// </summary> private WebProxy _Proxy = null; /// <summary> /// 连接FTP服务器的代理服务 /// </summary> public WebProxy Proxy { get { return _Proxy; } set { _Proxy = value; } } /// <summary> /// 是否需要删除临时文件 /// </summary> private bool _isDeleteTempFile = false; /// <summary> /// 异步上传所临时生成的文件 /// </summary> private string _UploadTempFile = ""; #endregion #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); /// <summary> /// 异步下载进度发生改变触发的事件 /// </summary> public event De_DownloadProgressChanged DownloadProgressChanged; /// <summary> /// 异步下载文件完成之后触发的事件 /// </summary> public event De_DownloadDataCompleted DownloadDataCompleted; /// <summary> /// 异步上传进度发生改变触发的事件 /// </summary> public event De_UploadProgressChanged UploadProgressChanged; /// <summary> /// 异步上传文件完成之后触发的事件 /// </summary> public event De_UploadFileCompleted UploadFileCompleted; #endregion #region 构造析构函数 /// <summary> /// 构造函数 /// </summary> /// <param name="FtpUri">FTP地址</param> /// <param name="strUserName">登录用户名</param> /// <param name="strPassword">登录密码</param> public clsFTP(Uri FtpUri, string strUserName, string strPassword) { this._Uri = new Uri(FtpUri.GetLeftPart(UriPartial.Authority)); _DirectoryPath = FtpUri.AbsolutePath; if (!_DirectoryPath.EndsWith("/")) { _DirectoryPath += "/"; } this._UserName = strUserName; this._Password = strPassword; this._Proxy = null; } /// <summary> /// 构造函数 /// </summary> /// <param name="FtpUri">FTP地址</param> /// <param name="strUserName">登录用户名</param> /// <param name="strPassword">登录密码</param> /// <param name="objProxy">连接代理</param> public clsFTP(Uri FtpUri, string strUserName, string strPassword, WebProxy objProxy) { this._Uri = new Uri(FtpUri.GetLeftPart(UriPartial.Authority)); _DirectoryPath = FtpUri.AbsolutePath; if (!_DirectoryPath.EndsWith("/")) { _DirectoryPath += "/"; } this._UserName = strUserName; this._Password = strPassword; this._Proxy = objProxy; } /// <summary> /// 构造函数 /// </summary> public clsFTP() { this._UserName = "anonymous"; //匿名用户 this._Password = "@anonymous"; this._Uri = null; this._Proxy = null; } /// <summary> /// 析构函数 /// </summary> ~clsFTP() { if (Response != null) { Response.Close(); Response = null; } if (Request != null) { Request.Abort(); Request = null; } } #endregion #region 建立连接 /// <summary> /// 建立FTP链接,返回响应对象 /// </summary> /// <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; } } /// <summary> /// 建立FTP链接,返回请求对象 /// </summary> /// <param name="uri">FTP地址</param> /// <param name="FtpMathod">操作命令</param> private FtpWebRequest OpenRequest(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 Request; } catch (Exception ep) { ErrorMsg = ep.ToString(); throw ep; } } #endregion #region 下载文件 /// <summary> /// 从FTP服务器下载文件,使用与远程文件同名的文件名来保存文件 /// </summary> /// <param name="RemoteFileName">远程文件名</param> /// <param name="LocalPath">本地路径</param> public bool DownloadFile(string RemoteFileName, string LocalPath) { return DownloadFile(RemoteFileName, LocalPath, RemoteFileName); } /// <summary> /// 从FTP服务器下载文件,指定本地路径和本地文件名 /// </summary> /// <param name="RemoteFileName">远程文件名</param> /// <param name="LocalPath">本地路径</param> /// <param name="LocalFilePath">保存文件的本地路径,后面带有"\"</param> /// <param name="LocalFileName">保存本地的文件名</param> public bool DownloadFile(string RemoteFileName, string LocalPath, string LocalFileName) { byte[] bt = null; try { 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; } else { return false; } } catch (Exception ep) { ErrorMsg = ep.ToString(); throw ep; } } /// <summary> /// 从FTP服务器下载文件,返回文件二进制数据 /// </summary> /// <param name="RemoteFileName">远程文件名</param> public byte[] DownloadFile(string RemoteFileName) { try { if (!IsValidFileChars(RemoteFileName)) { throw new Exception("非法文件名或目录名!"); } 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(); } else { return null; } } catch (Exception ep) { ErrorMsg = ep.ToString(); throw ep; } } #endregion #region 异步下载文件 /// <summary> /// 从FTP服务器异步下载文件,指定本地路径和本地文件名 /// </summary> /// <param name="RemoteFileName">远程文件名</param> /// <param name="LocalPath">保存文件的本地路径,后面带有"\"</param> /// <param name="LocalFileName">保存本地的文件名</param> public void DownloadFileAsync(string RemoteFileName, string LocalPath, string LocalFileName) { byte[] bt = null; try { 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("当前路径下已经存在同名文件!"); } DownloadFileAsync(RemoteFileName, LocalFullPath); } catch (Exception ep) { ErrorMsg = ep.ToString(); throw ep; } } /// <summary> /// 从FTP服务器异步下载文件,指定本地完整路径文件名 /// </summary> /// <param name="RemoteFileName">远程文件名</param> /// <param name="LocalFullPath">本地完整路径文件名</param> public void DownloadFileAsync(string RemoteFileName, string LocalFullPath) { try { if (!IsValidFileChars(RemoteFileName)) { throw new Exception("非法文件名或目录名!"); } if (File.Exists(LocalFullPath)) { throw new Exception("当前路径下已经存在同名文件!"); } 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); if (this.Proxy != null) { client.Proxy = this.Proxy; } client.DownloadFileAsync(new Uri(this.Uri.ToString() + RemoteFileName), LocalFullPath); } catch (Exception ep) { ErrorMsg = ep.ToString(); throw ep; } } /// <summary> /// 异步下载文件完成之后触发的事件 /// </summary> /// <param name="sender">下载对象</param> /// <param name="e">数据信息对象</param> void client_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) { if (DownloadDataCompleted != null) { DownloadDataCompleted(sender, e); } } /// <summary> /// 异步下载进度发生改变触发的事件 /// </summary> /// <param name="sender">下载对象</param> /// <param name="e">进度信息对象</param> void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) { if (DownloadProgressChanged != null) { DownloadProgressChanged(sender, e); } } #endregion #region 上传文件 /// <summary> /// 上传文件到FTP服务器 /// </summary> /// <param name="LocalFullPath">本地带有完整路径的文件名</param> public bool UploadFile(string LocalFullPath) { return UploadFile(LocalFullPath, Path.GetFileName(LocalFullPath), false); } /// <summary> /// 上传文件到FTP服务器 /// </summary> /// <param name="LocalFullPath">本地带有完整路径的文件</param> /// <param name="OverWriteRemoteFile">是否覆盖远程服务器上面同名的文件</param> public bool UploadFile(string LocalFullPath, bool OverWriteRemoteFile) { return UploadFile(LocalFullPath, Path.GetFileName(LocalFullPath), OverWriteRemoteFile); } /// <summary> /// 上传文件到FTP服务器 /// </summary> /// <param name="LocalFullPath">本地带有完整路径的文件</param> /// <param name="RemoteFileName">要在FTP服务器上面保存文件名</param> public bool UploadFile(string LocalFullPath, string RemoteFileName) { return UploadFile(LocalFullPath, RemoteFileName, false); } /// <summary> /// 上传文件到FTP服务器 /// </summary> /// <param name="LocalFullPath">本地带有完整路径的文件名</param> /// <param name="RemoteFileName">要在FTP服务器上面保存文件名</param> /// <param name="OverWriteRemoteFile">是否覆盖远程服务器上面同名的文件</param> public bool UploadFile(string LocalFullPath, string RemoteFileName, bool OverWriteRemoteFile) { try { if (!IsValidFileChars(RemoteFileName) || !IsValidFileChars(Path.GetFileName(LocalFullPath)) || !IsValidPathChars(Path.GetDirectoryName(LocalFullPath))) { throw new Exception("非法文件名或目录名!"); } if (File.Exists(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多一点 Stream.Close(); return UploadFile(bt, RemoteFileName, OverWriteRemoteFile); } else { throw new Exception("本地文件不存在!"); } } catch (Exception ep) { ErrorMsg = ep.ToString(); throw ep; } } /// <summary> /// 上传文件到FTP服务器 /// </summary> /// <param name="FileBytes">上传的二进制数据</param> /// <param name="RemoteFileName">要在FTP服务器上面保存文件名</param> public bool UploadFile(byte[] FileBytes, string RemoteFileName) { if (!IsValidFileChars(RemoteFileName)) { throw new Exception("非法文件名或目录名!"); } return UploadFile(FileBytes, RemoteFileName, false); } /// <summary> /// 上传文件到FTP服务器 /// </summary> /// <param name="FileBytes">文件二进制内容</param> /// <param name="RemoteFileName">要在FTP服务器上面保存文件名</param> /// <param name="OverWriteRemoteFile">是否覆盖远程服务器上面同名的文件</param> public bool UploadFile(byte[] FileBytes, string RemoteFileName, bool OverWriteRemoteFile) { try { if (!IsValidFileChars(RemoteFileName)) { 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); byte[] buffer = new byte[1024]; int bytesRead = 0; int TotalRead = 0; while (true) { bytesRead = mem.Read(buffer, 0, buffer.Length); if (bytesRead == 0) break; TotalRead += bytesRead; requestStream.Write(buffer, 0, bytesRead); } requestStream.Close(); Response = (FtpWebResponse) Request.GetResponse(); mem.Close(); mem.Dispose(); FileBytes = null; return true; } catch (Exception ep) { ErrorMsg = ep.ToString(); throw ep; } } #endregion #region 异步上传文件 /// <summary> /// 异步上传文件到FTP服务器 /// </summary> /// <param name="LocalFullPath">本地带有完整路径的文件名</param> public void UploadFileAsync(string LocalFullPath) { UploadFileAsync(LocalFullPath, Path.GetFileName(LocalFullPath), false); } /// <summary> /// 异步上传文件到FTP服务器 /// </summary> /// <param name="LocalFullPath">本地带有完整路径的文件</param> /// <param name="OverWriteRemoteFile">是否覆盖远程服务器上面同名的文件</param> public void UploadFileAsync(string LocalFullPath, bool OverWriteRemoteFile) { UploadFileAsync(LocalFullPath, Path.GetFileName(LocalFullPath), OverWriteRemoteFile); } /// <summary> /// 异步上传文件到FTP服务器 /// </summary> /// <param name="LocalFullPath">本地带有完整路径的文件</param> /// <param name="RemoteFileName">要在FTP服务器上面保存文件名</param> public void UploadFileAsync(string LocalFullPath, string RemoteFileName) { UploadFileAsync(LocalFullPath, RemoteFileName, false); } /// <summary> /// 异步上传文件到FTP服务器 /// </summary> /// <param name="LocalFullPath">本地带有完整路径的文件名</param> /// <param name="RemoteFileName">要在FTP服务器上面保存文件名</param> /// <param name="OverWriteRemoteFile">是否覆盖远程服务器上面同名的文件</param> public void UploadFileAsync(string LocalFullPath, string RemoteFileName, bool OverWriteRemoteFile) { try { if (!IsValidFileChars(RemoteFileName) || !IsValidFileChars(Path.GetFileName(LocalFullPath)) || !IsValidPathChars(Path.GetDirectoryName(LocalFullPath))) { throw new Exception("非法文件名或目录名!"); } if (!OverWriteRemoteFile && FileExist(RemoteFileName)) { throw new Exception("FTP服务上面已经存在同名文件!"); } if (File.Exists(LocalFullPath)) { MyWebClient client = new MyWebClient(); client.UploadProgressChanged += new UploadProgressChangedEventHandler(client_UploadProgressChanged); client.UploadFileCompleted += new UploadFileCompletedEventHandler(client_UploadFileCompleted); client.Credentials = new NetworkCredential(this.UserName, this.Password); if (this.Proxy != null) { client.Proxy = this.Proxy; } client.UploadFileAsync(new Uri(this.Uri.ToString() + RemoteFileName), LocalFullPath); } else { throw new Exception("本地文件不存在!"); } } catch (Exception ep) { ErrorMsg = ep.ToString(); throw ep; } } /// <summary> /// 异步上传文件到FTP服务器 /// </summary> /// <param name="FileBytes">上传的二进制数据</param> /// <param name="RemoteFileName">要在FTP服务器上面保存文件名</param> public void UploadFileAsync(byte[] FileBytes, string RemoteFileName) { if (!IsValidFileChars(RemoteFileName)) { throw new Exception("非法文件名或目录名!"); } UploadFileAsync(FileBytes, RemoteFileName, false); } /// <summary> /// 异步上传文件到FTP服务器 /// </summary> /// <param name="FileBytes">文件二进制内容</param> /// <param name="RemoteFileName">要在FTP服务器上面保存文件名</param> /// <param name="OverWriteRemoteFile">是否覆盖远程服务器上面同名的文件</param> public void UploadFileAsync(byte[] FileBytes, string RemoteFileName, bool OverWriteRemoteFile) { try { if (!IsValidFileChars(RemoteFileName)) { throw new Exception("非法文件名!"); } if (!OverWriteRemoteFile && FileExist(RemoteFileName)) { throw new Exception("FTP服务上面已经存在同名文件!"); } 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.Flush(); Stream.Close(); Stream.Dispose(); _isDeleteTempFile = true; _UploadTempFile = TempFile; FileBytes = null; UploadFileAsync(TempFile, RemoteFileName, OverWriteRemoteFile); } catch (Exception ep) { ErrorMsg = ep.ToString(); throw ep; } } /// <summary> /// 异步上传文件完成之后触发的事件 /// </summary> /// <param name="sender">下载对象</param> /// <param name="e">数据信息对象</param> 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); } } /// <summary> /// 异步上传进度发生改变触发的事件 /// </summary> /// <param name="sender">下载对象</param> /// <param name="e">进度信息对象</param> void client_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e) { if (UploadProgressChanged != null) { UploadProgressChanged(sender, e); } } #endregion #region 列出目录文件信息 /// <summary> /// 列出FTP服务器上面当前目录的所有文件和目录 /// </summary> 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; } /// <summary> /// 列出FTP服务器上面当前目录的所有文件 /// </summary> 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(); } /// <summary> /// 列出FTP服务器上面当前目录的所有的目录 /// </summary> public FileStruct[] ListDirectories() { FileStruct[] listAll = ListFilesAndDirectories(); List<FileStruct> listDirectory = new List<FileStruct>(); foreach (FileStruct file in listAll) { if (file.IsDirectory) { listDirectory.Add(file); } } return listDirectory.ToArray(); } /// <summary> /// 获得文件和目录列表 /// </summary> /// <param name="datastring">FTP返回的列表字符信息</param> private FileStruct[] GetList(string datastring) { List<FileStruct> myListArray = new List<FileStruct>(); string[] dataRecords = datastring.Split('\n'); 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); break; case FileListStyle.WindowsStyle: f = ParseFileStructFromWindowsStyleRecord(s); break; } if (!(f.Name == "." || f.Name == "..")) { myListArray.Add(f); } } } return myListArray.ToArray(); } /// <summary> /// 从Windows格式中返回文件信息 /// </summary> /// <param name="Record">文件信息</param> private FileStruct ParseFileStructFromWindowsStyleRecord(string Record) { FileStruct f = new FileStruct(); 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(); } else { string[] strs = processstr.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); // true); processstr = strs[1]; f.IsDirectory = false; } f.Name = processstr; return f; } /// <summary> /// 判断文件列表的方式Window方式还是Unix方式 /// </summary> /// <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; } /// <summary> /// 从Unix格式中返回文件信息 /// </summary> /// <param name="Record">文件信息</param> private FileStruct ParseFileStructFromUnixStyleRecord(string Record) { FileStruct f = new FileStruct(); string processstr = Record.Trim(); 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); _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; //最后就是名称 return f; } /// <summary> /// 按照一定的规则进行字符串截取 /// </summary> /// <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; } #endregion #region 目录或文件存在的判断 /// <summary> /// 判断当前目录下指定的子目录是否存在 /// </summary> /// <param name="RemoteDirectoryName">指定的目录名</param> public bool DirectoryExist(string RemoteDirectoryName) { try { if (!IsValidPathChars(RemoteDirectoryName)) { throw new Exception("目录名非法!"); } FileStruct[] listDir = ListDirectories(); foreach (FileStruct dir in listDir) { if (dir.Name == RemoteDirectoryName) { return true; } } return false; } catch (Exception ep) { ErrorMsg = ep.ToString(); throw ep; } } /// <summary> /// 判断一个远程文件是否存在服务器当前目录下面 /// </summary> /// <param name="RemoteFileName">远程文件名</param> public bool FileExist(string RemoteFileName) { try { if (!IsValidFileChars(RemoteFileName)) { throw new Exception("文件名非法!"); } FileStruct[] listFile = ListFiles(); foreach (FileStruct file in listFile) { if (file.Name == RemoteFileName) { return true; } } return false; } catch (Exception ep) { ErrorMsg = ep.ToString(); throw ep; } } #endregion #region 删除文件 /// <summary> /// 从FTP服务器上面删除一个文件 /// </summary> /// <param name="RemoteFileName">远程文件名</param> public void DeleteFile(string RemoteFileName) { try { if (!IsValidFileChars(RemoteFileName)) { throw new Exception("文件名非法!"); } Response = Open(new Uri(this.Uri.ToString() + RemoteFileName), WebRequestMethods.Ftp.DeleteFile); } catch (Exception ep) { ErrorMsg = ep.ToString(); throw ep; } } #endregion #region 重命名文件 /// <summary> /// 更改一个文件的名称或一个目录的名称 /// </summary> /// <param name="RemoteFileName">原始文件或目录名称</param> /// <param name="NewFileName">新的文件或目录的名称</param> public bool ReName(string RemoteFileName, string NewFileName) { try { if (!IsValidFileChars(RemoteFileName) || !IsValidFileChars(NewFileName)) { throw new Exception("文件名非法!"); } if (RemoteFileName == NewFileName) { return true; } if (FileExist(RemoteFileName)) { Request = OpenRequest(new Uri(this.Uri.ToString() + RemoteFileName), WebRequestMethods.Ftp.Rename); Request.RenameTo = NewFileName; Response = (FtpWebResponse) Request.GetResponse(); } else { throw new Exception("文件在服务器上不存在!"); } return true; } catch (Exception ep) { ErrorMsg = ep.ToString(); throw ep; } } #endregion #region 拷贝、移动文件 /// <summary> /// 把当前目录下面的一个文件拷贝到服务器上面另外的目录中,注意,拷贝文件之后,当前工作目录还是文件原来所在的目录 /// </summary> /// <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; try { byte[] bt = DownloadFile(RemoteFile); GotoDirectory(DirectoryName); bool Success = UploadFile(bt, RemoteFile, false); this.DirectoryPath = CurrentWorkDir; return Success; } catch (Exception ep) { this.DirectoryPath = CurrentWorkDir; ErrorMsg = ep.ToString(); throw ep; } } /// <summary> /// 把当前目录下面的一个文件移动到服务器上面另外的目录中,注意,移动文件之后,当前工作目录还是文件原来所在的目录 /// </summary> /// <param name="RemoteFile">当前目录下的文件名</param> /// <param name="DirectoryName">新目录名称。 /// 说明:如果新目录是当前目录的子目录,则直接指定子目录。如: SubDirectory1/SubDirectory2 ; /// 如果新目录不是当前目录的子目录,则必须从根目录一级一级的指定。如: ./NewDirectory/SubDirectory1/SubDirectory2 /// </param> /// <returns></returns> public bool MoveFileToAnotherDirectory(string RemoteFile, string DirectoryName) { string CurrentWorkDir = this.DirectoryPath; try { if (DirectoryName == "") return false; if (!DirectoryName.StartsWith("/")) DirectoryName = "/" + DirectoryName; if (!DirectoryName.EndsWith("/")) DirectoryName += "/"; bool Success = ReName(RemoteFile, DirectoryName + RemoteFile); this.DirectoryPath = CurrentWorkDir; return Success; } catch (Exception ep) { this.DirectoryPath = CurrentWorkDir; ErrorMsg = ep.ToString(); throw ep; } } #endregion #region 建立、删除子目录 /// <summary> /// 在FTP服务器上当前工作目录建立一个子目录 /// </summary> /// <param name="DirectoryName">子目录名称</param> public bool MakeDirectory(string DirectoryName) { try { if (!IsValidPathChars(DirectoryName)) { throw new Exception("目录名非法!"); } if (DirectoryExist(DirectoryName)) { throw new Exception("服务器上面已经存在同名的文件名或目录名!"); } Response = Open(new Uri(this.Uri.ToString() + DirectoryName), WebRequestMethods.Ftp.MakeDirectory); return true; } catch (Exception ep) { ErrorMsg = ep.ToString(); throw ep; } } /// <summary> /// 从当前工作目录中删除一个子目录 /// </summary> /// <param name="DirectoryName">子目录名称</param> public bool RemoveDirectory(string DirectoryName) { try { if (!IsValidPathChars(DirectoryName)) { throw new Exception("目录名非法!"); } if (!DirectoryExist(DirectoryName)) { throw new Exception("服务器上面不存在指定的文件名或目录名!"); } Response = Open(new Uri(this.Uri.ToString() + DirectoryName), WebRequestMethods.Ftp.RemoveDirectory); return true; } catch (Exception ep) { ErrorMsg = ep.ToString(); throw ep; } } #endregion #region 文件、目录名称有效性判断 /// <summary> /// 判断目录名中字符是否合法 /// </summary> /// <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) { return false; } } return true; } /// <summary> /// 判断文件名中字符是否合法 /// </summary> /// <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) { return false; } } return true; } #endregion #region 目录切换操作 /// <summary> /// 进入一个目录 /// </summary> /// <param name="DirectoryName"> /// 新目录的名字。 /// 说明:如果新目录是当前目录的子目录,则直接指定子目录。如: SubDirectory1/SubDirectory2 ; /// 如果新目录不是当前目录的子目录,则必须从根目录一级一级的指定。如: ./NewDirectory/SubDirectory1/SubDirectory2 /// </param> public bool GotoDirectory(string DirectoryName) { string CurrentWorkPath = this.DirectoryPath; try { DirectoryName = DirectoryName.Replace("\\", "/"); string[] DirectoryNames = DirectoryName.Split(new char[] { '/' }); if (DirectoryNames[0] == ".") { this.DirectoryPath = "/"; if (DirectoryNames.Length == 1) { return true; } Array.Clear(DirectoryNames, 0, 1); } bool Success = false; foreach (string dir in DirectoryNames) { if (dir != null) { Success = EnterOneSubDirectory(dir); if (!Success) { this.DirectoryPath = CurrentWorkPath; return false; } } } return Success; } catch (Exception ep) { this.DirectoryPath = CurrentWorkPath; ErrorMsg = ep.ToString(); throw ep; } } /// <summary> /// 从当前工作目录进入一个子目录 /// </summary> /// <param name="DirectoryName">子目录名称</param> private bool EnterOneSubDirectory(string DirectoryName) { try { if (DirectoryName.IndexOf("/") >= 0 || !IsValidPathChars(DirectoryName)) { throw new Exception("目录名非法!"); } if (DirectoryName.Length > 0 && DirectoryExist(DirectoryName)) { if (!DirectoryName.EndsWith("/")) { DirectoryName += "/"; } _DirectoryPath += DirectoryName; return true; } else { return false; } } catch (Exception ep) { ErrorMsg = ep.ToString(); throw ep; } } /// <summary> /// 从当前工作目录往上一级目录 /// </summary> public bool ComeoutDirectory() { if (_DirectoryPath == "/") { ErrorMsg = "当前目录已经是根目录!"; throw new Exception("当前目录已经是根目录!"); } char[] sp = new char[1] { '/' }; string[] strDir = _DirectoryPath.Split(sp, StringSplitOptions.RemoveEmptyEntries); if (strDir.Length == 1) { _DirectoryPath = "/"; } else { _DirectoryPath = String.Join("/", strDir, 0, strDir.Length - 1); } return true; } #endregion #region 重载WebClient,支持FTP进度 internal class MyWebClient : WebClient { protected override WebRequest GetWebRequest(Uri address) { FtpWebRequest req = (FtpWebRequest) base.GetWebRequest(address); req.UsePassive = false; return req; } } #endregion } }
例子:
调用方法,目前只用上传功能:
定义全局私有变量:
private clsFTP cf;
按钮事件:
private void btn_upFile_Click(object sender, EventArgs e)
{
lb_upload.Text = "正在上传文件,请等待...";
cf = new clsFTP(new Uri("http://www.cnblogs.com/zhangjun1130/admin/ftp://192.168.43.55/"), "temp", "temp");
string localFile = Application.StartupPath.ToString() + "http://www.cnblogs.com/zhangjun1130/admin/file://output//zt.rar";
cf.UploadProgressChanged+=new clsFTP.De_UploadProgressChanged(cf_UploadProgressChanged);
cf.UploadFileCompleted+=new clsFTP.De_UploadFileCompleted(cf_UploadFileCompleted);
cf.UploadFileAsync(localFile, true); //调用异步传输,若有文件存在则覆盖。
}
事件捆绑,反映上传进度:
public void cf_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
{
this.pgrBarFileUpload.Maximum = (int)e.TotalBytesToSend;
this.pgrBarFileUpload.Value =(int) e.BytesSent;
lb_upload.Text = string.Format("文件总大小:{0}k,已经上传: {1}k。", e.TotalBytesToSend/1024,e.BytesSent/1024);
}
public void cf_UploadFileCompleted(object sender, UploadFileCompletedEventArgs e)
{
try
{
lb_upload.Text = "无法连接到服务器,或者用户登陆失败!";
lb_error.Text =e.Error.Message.ToString();
}
catch
{
lb_upload.Text = "文件上传成功!";
lb_error.Text = "";
}
}
本文来源于Woody的鸟窝(Woody's Blog) http://www.smartgz.com/, 原文地址:http://www.smartgz.com/blog/Article/1107.asp