簡單實用的FTP操作類
最近公司的項目需要使用FTP進行文件同步操作,原系統里有一個FTP操作類,不過封裝的很不好(反正我看著很別扭),干脆自己按照自己的風格重新寫了一個。這里主要參考了園子里南瘋封裝的clsFTP類,個人感覺這個類功能比較強大,個人用不到那么多功能所以按照自己的使用習慣重寫了個簡化的類。
只實現了基本的上傳、下載、判斷文件是否存在及我實際應用中最重要的根據選擇的遠程文件地址自動創建相關目錄功能
具體代碼下載:FtpHelper
編輯器插入Code總是報錯只能直接貼代碼了,汗。。。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
using System.Globalization;
namespace System.Helper
{
/// <summary>
/// 創建者:懶惰的肥兔
/// FTP操作類
/// 只支持基本的文件上傳、下載、目錄遞歸創建、文件目錄列表獲取
/// </summary>
public class FtpHelper
{
#region 屬性
/// <summary>
/// 獲取或設置用戶名
/// </summary>
public string UserName { get; set; }
/// <summary>
/// 獲取或設置密碼
/// </summary>
public string Password { get; set; }
/// <summary>
/// 異常信息
/// </summary>
public string ErrorMsg { get; set; }
/// <summary>
/// Exception
/// </summary>
public Exception Exception { get; set; }
/// <summary>
/// 狀態
/// </summary>
public FtpStatusCode StatusCode { get; set; }
/// <summary>
/// 狀態描述
/// </summary>
public string StatusDescription { get; set; }
/// <summary>
/// 獲取或設置FTP服務器地址
/// </summary>
public Uri Uri { get; set; }
/// <summary>
/// 獲取或者是讀取文件、目錄列表時所使用的編碼,默認為UTF-8
/// </summary>
public Encoding Encode { get; set; }
#endregion
#region 構造函數
public FtpHelper(Uri uri, string username, string password)
{
this.Uri = uri;
this.UserName = username;
this.Password = password;
this.Encode = Encoding.GetEncoding("utf-8");
}
#endregion
#region 建立連接
/// <summary>
/// 建立FTP鏈接,返回請求對象
/// </summary>
/// <param name="uri">FTP地址</param>
/// <param name="method">操作命令(WebRequestMethods.Ftp)</param>
/// <returns></returns>
private FtpWebRequest CreateRequest(Uri uri, string method)
{
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(uri);
request.Credentials = new NetworkCredential(this.UserName, this.Password);//指定登錄ftp服務器的用戶名和密碼。
request.KeepAlive = false;//指定連接是應該關閉還是在請求完成之后關閉,默認為true
request.UsePassive = true;//指定使用被動模式,默認為true
request.UseBinary = true;//指示服務器要傳輸的是二進制數據.false,指示數據為文本。默認值為true
request.EnableSsl = false;//如果控制和數據傳輸是加密的,則為true.否則為false.默認值為 false
request.Method = method;
return request;
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// 建立FTP鏈接,返回響應對象
/// </summary>
/// <param name="uri">FTP地址</param>
/// <param name="method">操作命令(WebRequestMethods.Ftp)</param>
/// <returns></returns>
private FtpWebResponse CreateResponse(Uri uri, string method)
{
try
{
FtpWebRequest request = CreateRequest(uri, method);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
this.StatusCode = response.StatusCode;
this.StatusDescription = response.StatusDescription;
return response;
}
catch (WebException ex)
{
FtpWebResponse response = ex.Response as FtpWebResponse;
if (response != null)
{
this.StatusCode = response.StatusCode;
this.StatusDescription = response.StatusDescription;
}
throw ex;
}
}
#endregion
#region 上傳文件
/// <summary>
/// 上傳文件到FTP服務器,若文件已存在自動覆蓋
/// 本方法不會自動創建遠程路徑的目錄
/// </summary>
/// <param name="localFilePath">本地帶有完整路徑的文件名</param>
/// <param name="remoteFilePath">要在FTP服務器上面保存完整文件名</param>
public bool UploadFile(string localFilePath, string remoteFilePath)
{
return UploadFile(localFilePath, remoteFilePath, false);
}
/// <summary>
/// 上傳文件到FTP服務器,若文件已存在自動覆蓋
/// </summary>
/// <param name="localFilePath">本地帶有完整路徑的文件名</param>
/// <param name="remoteFilePath">要在FTP服務器上面保存完整文件名</param>
/// <param name="autoCreateDirectory">是否自動遞歸創建文件目錄</param>
/// <returns></returns>
public bool UploadFile(string localFilePath, string remoteFilePath, bool autoCreateDirectory)
{
try
{
//自動遞歸創建目錄
if (autoCreateDirectory)
{
if (!CreateDirectory(Path.GetDirectoryName(remoteFilePath)))
{
//遞歸創建目錄失敗,返回false
return false;
}
}
FileInfo fileInf = new FileInfo(localFilePath);
if (!fileInf.Exists)
{
throw new FileNotFoundException(string.Format("本地文件不存在:{0}!", localFilePath));
}
FtpWebRequest request = CreateRequest(new Uri(this.Uri + remoteFilePath), WebRequestMethods.Ftp.UploadFile);
request.ContentLength = fileInf.Length;
int contentLen = 0;
//緩沖2kb
byte[] buff = new byte[2048];
using (FileStream fs = fileInf.OpenRead())
{
using (Stream stream = request.GetRequestStream())
{
while ((contentLen = fs.Read(buff, 0, buff.Length)) > 0)
{
stream.Write(buff, 0, contentLen);
}
}
}
return true;
}
catch (Exception ex)
{
this.Exception = ex;
this.ErrorMsg = ex.Message;
}
return false;
}
#endregion
#region 下載文件
/// <summary>
/// 從FTP服務器下載文件
/// </summary>
/// <param name="remoteFilePath">遠程完整文件名</param>
/// <param name="localFilePath">本地帶有完整路徑的文件名</param>
public bool DownloadFile(string remoteFilePath, string localFilePath)
{
try
{
string localDirector = Path.GetDirectoryName(localFilePath);
if (!Directory.Exists(localDirector))
{
Directory.CreateDirectory(localDirector);
}
FtpWebResponse response = CreateResponse(new Uri(this.Uri + remoteFilePath), WebRequestMethods.Ftp.DownloadFile);
byte[] buffer = new byte[2048];
int bytesCount = 0;
Stream stream = response.GetResponseStream();
using (FileStream fs = new FileStream(localFilePath, FileMode.Create))
{
while ((bytesCount = stream.Read(buffer, 0, buffer.Length)) > 0)
{
fs.Write(buffer, 0, bytesCount);
}
}
return true;
}
catch (Exception ex)
{
this.Exception = ex;
this.ErrorMsg = ex.Message;
}
return false;
}
#endregion
#region 移動、重命名文件
/// <summary>
/// 移動遠程文件文件
/// </summary>
/// <param name="remoteFileName">遠程文件名</param>
/// <param name="newFileName">新文件名</param>
/// <returns></returns>
public bool MoveFile(string remoteFileName, string newFileName)
{
return ReName(remoteFileName, newFileName);
}
/// <summary>
/// 重命名遠程文件
/// </summary>
/// <param name="remoteFileName">遠程文件名</param>
/// <param name="newFileName">新文件名</param>
/// <returns></returns>
public bool ReName(string remoteFileName, string newFileName)
{
try
{
if (remoteFileName != newFileName)
{
FtpWebRequest request = CreateRequest(new Uri(this.Uri + remoteFileName), WebRequestMethods.Ftp.Rename);
request.RenameTo = newFileName;
request.GetResponse();
}
return true;
}
catch (WebException ex)
{
this.ErrorMsg = ex.Message;
this.Exception = ex;
FtpWebResponse response = ex.Response as FtpWebResponse;
if (response != null)
{
this.StatusCode = response.StatusCode;
this.StatusDescription = response.StatusDescription;
}
}
return false;
}
#endregion
#region 刪除文件
/// <summary>
/// 刪除遠程文件
/// </summary>
/// <param name="fileName"></param>
/// <returns>成功返回True,否則返回False</returns>
public bool DeleteFile(string fileName)
{
try
{
CreateResponse(new Uri(this.Uri + fileName), WebRequestMethods.Ftp.DeleteFile);
return true;
}
catch (Exception ex)
{
this.Exception = ex;
this.ErrorMsg = ex.Message;
}
return false;
}
#endregion
#region 遞歸創建目錄
/// <summary>
/// 遞歸創建目錄,在創建目錄前不進行目錄是否已存在檢測
/// </summary>
/// <param name="remoteDirectory"></param>
public bool CreateDirectory(string remoteDirectory)
{
return CreateDirectory(remoteDirectory, false);
}
/// <summary>
/// 在FTP服務器遞歸創建目錄
/// </summary>
/// <param name="remoteDirectory">要創建的目錄</param>
/// <param name="autoCheckExist">創建目錄前是否進行目錄是否存在檢測</param>
/// <returns></returns>
public bool CreateDirectory(string remoteDirectory, bool autoCheckExist)
{
try
{
string parentDirector = "/";
if (!string.IsNullOrEmpty(remoteDirectory))
{
remoteDirectory = remoteDirectory.Replace("\\", "/");
string[] directors = remoteDirectory.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string director in directors)
{
if (!parentDirector.EndsWith("/")) parentDirector += "/";
if (autoCheckExist)
{
if (!DirectoryExist(parentDirector, director))
CreateResponse(new Uri(this.Uri + parentDirector + director), WebRequestMethods.Ftp.MakeDirectory);
}
else
{
try
{
CreateResponse(new Uri(this.Uri + parentDirector + director), WebRequestMethods.Ftp.MakeDirectory);
}
catch (WebException ex)
{
if (this.StatusCode != FtpStatusCode.ActionNotTakenFileUnavailable)
{
throw ex;
}
}
}
parentDirector += director;
}
}
return true;
}
catch (WebException ex)
{
this.Exception = ex;
this.ErrorMsg = ex.Message;
}
return false;
}
/// <summary>
/// 檢測指定目錄下是否存在指定的目錄名
/// </summary>
/// <param name="parentDirector"></param>
/// <param name="directoryName"></param>
/// <returns></returns>
private bool DirectoryExist(string parentDirector, string directoryName)
{
List<FileStruct> list = GetFileAndDirectoryList(parentDirector);
foreach (FileStruct fstruct in list)
{
if (fstruct.IsDirectory && fstruct.Name == directoryName)
{
return true;
}
}
return false;
}
#endregion
#region 檢測文件是否已存在
/// <summary>
/// 檢測FTP服務器上是否存在指定文件
/// 中文文件名若存在無法正確檢測現在有肯能是編碼問題所致
/// 請調用this.Encode進行文件編碼設置,默認為UTF-8,一般改為GB2312就能正確識別
/// </summary>
/// <param name="remoteFilePath"></param>
/// <returns></returns>
public bool FileExist(string remoteFilePath)
{
List<FileStruct> list = GetFileAndDirectoryList(Path.GetDirectoryName(remoteFilePath));
foreach (FileStruct fstruct in list)
{
if (!fstruct.IsDirectory && fstruct.Name == Path.GetFileName(remoteFilePath))
{
return true;
}
}
return false;
}
#endregion
#region 目錄、文件列表
/// <summary>
/// 獲取FTP服務器上指定目錄下的所有文件和目錄
/// 若獲取的中文文件、目錄名優亂碼現象
/// 請調用this.Encode進行文件編碼設置,默認為UTF-8,一般改為GB2312就能正確識別
/// </summary>
/// <param name="direcotry"></param>
/// <returns></returns>
public List<FileStruct> GetFileAndDirectoryList(string direcotry)
{
try
{
List<FileStruct> list = new List<FileStruct>();
string str = null;
//WebRequestMethods.Ftp.ListDirectoryDetails可以列出所有的文件和目錄列表
//WebRequestMethods.Ftp.ListDirectory只能列出目錄的文件列表
FtpWebResponse response = CreateResponse(new Uri(this.Uri.ToString() + direcotry), WebRequestMethods.Ftp.ListDirectoryDetails);
Stream stream = response.GetResponseStream();
using (StreamReader sr = new StreamReader(stream, this.Encode))
{
str = sr.ReadToEnd();
}
string[] fileList = str.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
EFileListFormat format = JudgeFileListFormat(fileList);
if (!string.IsNullOrEmpty(str) && format != EFileListFormat.Unknown)
{
list = ParseFileStruct(fileList, format);
}
return list;
}
catch (WebException ex)
{
throw ex;
}
}
/// <summary>
/// 解析文件列表信息返回文件列表
/// </summary>
/// <param name="fileList"></param>
/// <param name="format">文件列表格式</param>
/// <returns></returns>
private List<FileStruct> ParseFileStruct(string[] fileList, EFileListFormat format)
{
List<FileStruct> list = new List<FileStruct>();
if (format == EFileListFormat.UnixFormat)
{
foreach (string info in fileList)
{
FileStruct fstuct = new FileStruct();
fstuct.Origin = info.Trim();
fstuct.OriginArr = fstuct.Origin.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (fstuct.OriginArr.Length == 9)
{
fstuct.Flags = fstuct.OriginArr[0];
fstuct.IsDirectory = (fstuct.Flags[0] == 'd');
fstuct.Owner = fstuct.OriginArr[2];
fstuct.Group = fstuct.OriginArr[3];
fstuct.Size = Convert.ToInt32(fstuct.OriginArr[4]);
if (fstuct.OriginArr[7].Contains(":"))
{
fstuct.OriginArr[7] = DateTime.Now.Year + " " + fstuct.OriginArr[7];
}
fstuct.UpdateTime = DateTime.Parse(string.Format("{0} {1} {2}", fstuct.OriginArr[5], fstuct.OriginArr[6], fstuct.OriginArr[7]));
fstuct.Name = fstuct.OriginArr[8];
if (fstuct.Name != "." && fstuct.Name != "..")
{
list.Add(fstuct);
}
}
}
}
else if (format == EFileListFormat.WindowsFormat)
{
foreach (string info in fileList)
{
FileStruct fstuct = new FileStruct();
fstuct.Origin = info.Trim();
fstuct.OriginArr = fstuct.Origin.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (fstuct.OriginArr.Length == 4)
{
DateTimeFormatInfo usDate = new CultureInfo("en-US", false).DateTimeFormat;
usDate.ShortTimePattern = "t";
fstuct.UpdateTime = DateTime.Parse(fstuct.OriginArr[0] + " " + fstuct.OriginArr[1], usDate);
fstuct.IsDirectory = (fstuct.OriginArr[2] == "<DIR>");
if (!fstuct.IsDirectory)
{
fstuct.Size = Convert.ToInt32(fstuct.OriginArr[2]);
}
fstuct.Name = fstuct.OriginArr[3];
if (fstuct.Name != "." && fstuct.Name != "..")
{
list.Add(fstuct);
}
}
}
}
return list;
}
/// <summary>
/// 判斷文件列表的方式Window方式還是Unix方式
/// </summary>
/// <param name="fileList">文件信息列表</param>
/// <returns></returns>
private EFileListFormat JudgeFileListFormat(string[] fileList)
{
foreach (string str in fileList)
{
if (str.Length > 10 && Regex.IsMatch(str.Substring(0, 10), "(-|d)(-|r)(-|w)(-|x)(-|r)(-|w)(-|x)(-|r)(-|w)(-|x)"))
{
return EFileListFormat.UnixFormat;
}
else if (str.Length > 8 && Regex.IsMatch(str.Substring(0, 8), "[0-9][0-9]-[0-9][0-9]-[0-9][0-9]"))
{
return EFileListFormat.WindowsFormat;
}
}
return EFileListFormat.Unknown;
}
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.UpdateTime = 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;
}
#endregion
}
#region 文件結構
/// <summary>
/// 文件列表格式
/// </summary>
public enum EFileListFormat
{
/// <summary>
/// Unix文件格式
/// </summary>
UnixFormat,
/// <summary>
/// Window文件格式
/// </summary>
WindowsFormat,
/// <summary>
/// 未知格式
/// </summary>
Unknown
}
public struct FileStruct
{
public string Origin { get; set; }
public string[] OriginArr { get; set; }
public string Flags { get; set; }
/// <summary>
/// 所有者
/// </summary>
public string Owner { get; set; }
public string Group { get; set; }
/// <summary>
/// 是否為目錄
/// </summary>
public bool IsDirectory { get; set; }
/// <summary>
/// 文件或目錄更新時間
/// </summary>
public DateTime UpdateTime { get; set; }
/// <summary>
/// 文件或目錄名稱
/// </summary>
public string Name { get; set; }
/// <summary>
/// 文件大小(目錄始終為0)
/// </summary>
public int Size { get; set; }
}
#endregion
}
注:此文章屬懶惰的肥兔原創,版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接
若您覺得這篇文章還不錯請點擊下右下角的推薦,有了您的支持才能激發作者更大的寫作熱情,非常感謝。
如有問題,可以通過lzrabbit@126.com聯系我。
浙公網安備 33010602011771號