本文整理自網絡,由於太多文章類似,此處標識其中一處:點擊打開鏈接
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net.Sockets; using System.IO; using System.Net; namespace JianKunKing.Common.Ftp { ////// FTP Client(不允許匿名登錄) /// 上傳、下載已測試,其余未測試 /// public class FTPClient { #region 構造函數 ////// 缺省構造函數 /// public FTPClient() { this.ftpServerIP = ; this.remoteFilePath = ; this.ftpUserID = ; this.ftpPassword = ; this.ftpServerPort = 21; this.bConnected = false; } ////// 構造函數 /// ///FTP服務器IP地址 ///當前服務器目錄 ///Ftp 服務器登錄用戶賬號 ///Ftp 服務器登錄用戶密碼 ///FTP服務器端口 public FTPClient(string ftpServerIP, string remoteFilePath, string ftpUserID, string ftpPassword, int ftpServerPort, bool anonymousAccess = false) { this.ftpServerIP = ftpServerIP; this.remoteFilePath = remoteFilePath; this.ftpUserID = ftpUserID; this.ftpPassword = ftpPassword; this.ftpServerPort = ftpServerPort; this.Connect(); } #endregion #region 登陸字段、屬性 ////// FTP服務器IP地址 /// private string ftpServerIP; public string FtpServerIP { get { return ftpServerIP; } set { this.ftpServerIP = value; } } ////// FTP服務器端口 /// private int ftpServerPort; public int FtpServerPort { get { return ftpServerPort; } set { this.ftpServerPort = value; } } ////// 當前服務器目錄 /// private string remoteFilePath; public string RemoteFilePath { get { return remoteFilePath; } set { this.remoteFilePath = value; } } ////// Ftp 服務器登錄用戶賬號 /// private string ftpUserID; public string FtpUserID { set { this.ftpUserID = value; } } ////// Ftp 服務器用戶登錄密碼 /// private string ftpPassword; public string FtpPassword { set { this.ftpPassword = value; } } ////// 是否登錄 /// private bool bConnected; public bool Connected { get { return this.bConnected; } } #endregion #region 鏈接 ////// 建立連接 /// public void Connect() { socketControl = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint ep = new IPEndPoint(IPAddress.Parse(FtpServerIP), ftpServerPort); // 鏈接 try { socketControl.Connect(ep); } catch (Exception) { throw new IOException(Couldn't connect to remote server); } // 獲取應答碼 ReadReply(); if (iReplyCode != 220) { DisConnect(); throw new IOException(strReply.Substring(4)); } // 登陸 SendCommand(USER + ftpUserID); if (!(iReplyCode == 331 || iReplyCode == 230)) { CloseSocketConnect();//關閉連接 throw new IOException(strReply.Substring(4)); } if (iReplyCode != 230) { SendCommand(PASS + ftpPassword); if (!(iReplyCode == 230 || iReplyCode == 202)) { CloseSocketConnect();//關閉連接 throw new IOException(strReply.Substring(4)); } } bConnected = true; // 切換到初始目錄 if (!string.IsNullOrEmpty(remoteFilePath)) { ChDir(remoteFilePath); } } ////// 關閉連接 /// public void DisConnect() { if (socketControl != null) { SendCommand(QUIT); } CloseSocketConnect(); } #endregion #region 傳輸模式 ////// 傳輸模式:二進制類型、ASCII類型 /// public enum TransferType { Binary, ASCII }; ////// 設置傳輸模式 /// ///傳輸模式 public void SetTransferType(TransferType ttType) { if (ttType == TransferType.Binary) { SendCommand(TYPE I);//binary類型傳輸 } else { SendCommand(TYPE A);//ASCII類型傳輸 } if (iReplyCode != 200) { throw new IOException(strReply.Substring(4)); } else { trType = ttType; } } ////// 獲得傳輸模式 /// ///傳輸模式 public TransferType GetTransferType() { return trType; } #endregion #region 文件操作 ////// 獲得文件列表 /// ///文件名的匹配字符串 ///public string[] Dir(string strMask) { // 建立鏈接 if (!bConnected) { Connect(); } //建立進行數據連接的socket Socket socketData = CreateDataSocket(); //傳送命令 SendCommand(LIST + strMask); //分析應答代碼 if (!(iReplyCode == 150 || iReplyCode == 125 || iReplyCode == 226)) { throw new IOException(strReply.Substring(4)); } //獲得結果 strMsg = ; while (true) { int iBytes = socketData.Receive(buffer, buffer.Length, 0); strMsg += GB2312.GetString(buffer, 0, iBytes); if (iBytes < buffer.Length) { break; } } char[] seperator = { ' ' }; string[] strsFileList = strMsg.Split(seperator); socketData.Close();//數據socket關閉時也會有返回碼 if (iReplyCode != 226) { ReadReply(); if (iReplyCode != 226) { throw new IOException(strReply.Substring(4)); } } return strsFileList; } /// /// 獲取文件大小 /// ///文件名 ///文件大小 public long GetFileSize(string strFileName) { if (!bConnected) { Connect(); } SendCommand(SIZE + Path.GetFileName(strFileName)); long lSize = 0; if (iReplyCode == 213) { lSize = Int64.Parse(strReply.Substring(4)); } else { throw new IOException(strReply.Substring(4)); } return lSize; } ////// 刪除 /// ///待刪除文件名 public void Delete(string strFileName) { if (!bConnected) { Connect(); } SendCommand(DELE + strFileName); if (iReplyCode != 250) { throw new IOException(strReply.Substring(4)); } } ////// 重命名(如果新文件名與已有文件重名,將覆蓋已有文件) /// ///舊文件名 ///新文件名 public void Rename(string strOldFileName, string strNewFileName) { if (!bConnected) { Connect(); } SendCommand(RNFR + strOldFileName); if (iReplyCode != 350) { throw new IOException(strReply.Substring(4)); } // 如果新文件名與原有文件重名,將覆蓋原有文件 SendCommand(RNTO + strNewFileName); if (iReplyCode != 250) { throw new IOException(strReply.Substring(4)); } } #endregion #region 上傳和下載 ////// 下載一批文件 /// ///文件名的匹配字符串 ///本地目錄(不得以結束) public void Download(string strFileNameMask, string strFolder) { if (!bConnected) { Connect(); } string[] strFiles = Dir(strFileNameMask); foreach (string strFile in strFiles) { if (!strFile.Equals())//一般來說strFiles的最後一個元素可能是空字符串 { if (strFile.LastIndexOf(.) > -1) { Download(strFile.Replace( , ), strFolder, strFile.Replace( , )); } } } } ////// 下載目錄 /// ///要下載的文件名 ///本地目錄(不得以結束) ///保存在本地時的文件名 public void Download(string strRemoteFileName, string strFolder, string strLocalFileName) { if (strLocalFileName.StartsWith(-r)) { string[] infos = strLocalFileName.Split(' '); strRemoteFileName = strLocalFileName = infos[infos.Length - 1]; if (!this.bConnected) { this.Connect(); } SetTransferType(TransferType.Binary); if (strLocalFileName.Equals()) { strLocalFileName = strRemoteFileName; } if (!File.Exists(strLocalFileName)) { Stream st = File.Create(strLocalFileName); st.Close(); } FileStream output = new FileStream(strFolder + \ + strLocalFileName, FileMode.Create); Socket socketData = CreateDataSocket(); SendCommand(RETR + strRemoteFileName); if (!(iReplyCode == 150 || iReplyCode == 125 || iReplyCode == 226 || iReplyCode == 250)) { throw new IOException(strReply.Substring(4)); } int receiveBytes = 0; while (true) { int iBytes = socketData.Receive(buffer, buffer.Length, 0); receiveBytes = receiveBytes + iBytes; output.Write(buffer, 0, iBytes); if (iBytes <= 0) { break; } } output.Close(); if (socketData.Connected) { socketData.Close(); } if (!(iReplyCode == 226 || iReplyCode == 250)) { ReadReply(); if (!(iReplyCode == 226 || iReplyCode == 250)) { throw new IOException(strReply.Substring(4)); } } } } ////// 下載一個文件 /// ///要下載的文件名 ///本地目錄(不得以結束) ///保存在本地時的文件名 public void DownloadFile(string strRemoteFileName, string strFolder, string strLocalFileName) { if (!bConnected) { Connect(); } SetTransferType(TransferType.Binary); if (strLocalFileName.Equals()) { strLocalFileName = strRemoteFileName; } if (!File.Exists(strLocalFileName)) { Stream st = File.Create(strLocalFileName); st.Close(); } FileStream output = new FileStream(strFolder + \ + strLocalFileName, FileMode.Create); Socket socketData = CreateDataSocket(); SendCommand(RETR + strRemoteFileName); if (!(iReplyCode == 150 || iReplyCode == 125 || iReplyCode == 226 || iReplyCode == 250)) { throw new IOException(strReply.Substring(4)); } while (true) { int iBytes = socketData.Receive(buffer, buffer.Length, 0); output.Write(buffer, 0, iBytes); if (iBytes <= 0) { break; } } output.Close(); if (socketData.Connected) { socketData.Close(); } if (!(iReplyCode == 226 || iReplyCode == 250)) { ReadReply(); if (!(iReplyCode == 226 || iReplyCode == 250)) { throw new IOException(strReply.Substring(4)); } } } ////// 下載一個文件(斷點續傳) /// ///要下載的文件名 ///本地目錄(不得以結束) ///保存在本地時的文件名 ///已下載文件流長度 public void DownloadBrokenFile(string strRemoteFileName, string strFolder, string strLocalFileName, long size) { if (!bConnected) { Connect(); } SetTransferType(TransferType.Binary); FileStream output = new FileStream(strFolder + \ + strLocalFileName, FileMode.Append); Socket socketData = CreateDataSocket(); SendCommand(REST + size.ToString()); SendCommand(RETR + strRemoteFileName); if (!(iReplyCode == 150 || iReplyCode == 125 || iReplyCode == 226 || iReplyCode == 250)) { throw new IOException(strReply.Substring(4)); } while (true) { int iBytes = socketData.Receive(buffer, buffer.Length, 0); output.Write(buffer, 0, iBytes); if (iBytes <= 0) { break; } } output.Close(); if (socketData.Connected) { socketData.Close(); } if (!(iReplyCode == 226 || iReplyCode == 250)) { ReadReply(); if (!(iReplyCode == 226 || iReplyCode == 250)) { throw new IOException(strReply.Substring(4)); } } } ////// 上傳一批文件 /// ///本地目錄(不得以結束) ///文件名匹配字符(可以包含*和?) public void Upload(string strFolder, string strFileNameMask) { string[] strFiles = Directory.GetFiles(strFolder, strFileNameMask); foreach (string strFile in strFiles) { //strFile是完整的文件名(包含路徑) Upload(strFile); } } ////// 上傳一個文件 /// ///本地文件名 public void Upload(string strFileName) { if (!bConnected) { Connect(); } Socket socketData = CreateDataSocket(); SendCommand(STOR + Path.GetFileName(strFileName)); if (!(iReplyCode == 125 || iReplyCode == 150)) { throw new IOException(strReply.Substring(4)); } FileStream input = new FileStream(strFileName, FileMode.Open); int iBytes = 0; while ((iBytes = input.Read(buffer, 0, buffer.Length)) > 0) { socketData.Send(buffer, iBytes, 0); } input.Close(); if (socketData.Connected) { socketData.Close(); } if (!(iReplyCode == 226 || iReplyCode == 250)) { ReadReply(); if (!(iReplyCode == 226 || iReplyCode == 250)) { throw new IOException(strReply.Substring(4)); } } } #endregion #region 目錄操作 ////// 創建目錄 /// ///目錄名 public void MkDir(string strDirName) { if (!bConnected) { Connect(); } SendCommand(MKD + strDirName); if (iReplyCode != 257) { throw new IOException(strReply.Substring(4)); } } ////// 刪除目錄 /// ///目錄名 public void RmDir(string strDirName) { if (!bConnected) { Connect(); } SendCommand(RMD + strDirName); if (iReplyCode != 250) { throw new IOException(strReply.Substring(4)); } } ////// 改變目錄 /// ///新的工作目錄名 public void ChDir(string strDirName) { if (strDirName.Equals(.) || strDirName.Equals()) { return; } if (!bConnected) { Connect(); } SendCommand(CWD + strDirName); if (iReplyCode != 250) { throw new IOException(strReply.Substring(4)); } this.remoteFilePath = strDirName; } #endregion #region 內部變量 ////// 服務器返回的應答信息(包含應答碼) /// private string strMsg; ////// 服務器返回的應答信息(包含應答碼) /// private string strReply; ////// 服務器返回的應答碼 /// private int iReplyCode; ////// 進行控制連接的socket /// private Socket socketControl; ////// 傳輸模式 /// private TransferType trType; ////// 接收和發送數據的緩沖區 /// private static int BLOCK_SIZE = 512; Byte[] buffer = new Byte[BLOCK_SIZE]; ////// 編碼方式(為防止出現中文亂碼采用 GB2312編碼方式) /// Encoding GB2312 = Encoding.GetEncoding(gb2312); #endregion #region 內部函數 ////// 將一行應答字符串記錄在strReply和strMsg /// 應答碼記錄在iReplyCode /// private void ReadReply() { strMsg = ; strReply = ReadLine(); iReplyCode = Int32.Parse(strReply.Substring(0, 3)); } ////// 建立進行數據連接的socket /// ///數據連接socket private Socket CreateDataSocket() { SendCommand(PASV); if (iReplyCode != 227) { throw new IOException(strReply.Substring(4)); } int index1 = strReply.IndexOf('('); int index2 = strReply.IndexOf(')'); string ipData = strReply.Substring(index1 + 1, index2 - index1 - 1); int[] parts = new int[6]; int len = ipData.Length; int partCount = 0; string buf = ; for (int i = 0; i < len && partCount <= 6; i++) { char ch = Char.Parse(ipData.Substring(i, 1)); if (Char.IsDigit(ch)) buf += ch; else if (ch != ',') { throw new IOException(Malformed PASV strReply: + strReply); } if (ch == ',' || i + 1 == len) { try { parts[partCount++] = Int32.Parse(buf); buf = ; } catch (Exception) { throw new IOException(Malformed PASV strReply: + strReply); } } } string ipAddress = parts[0] + . + parts[1] + . + parts[2] + . + parts[3]; int port = (parts[4] << 8) + parts[5]; Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint ep = new IPEndPoint(IPAddress.Parse(ipAddress), port); try { s.Connect(ep); } catch (Exception) { throw new IOException(Can't connect to remote server); } return s; } ////// 關閉socket連接(用於登錄以前) /// private void CloseSocketConnect() { if (socketControl != null) { socketControl.Close(); socketControl = null; } bConnected = false; } ////// 讀取Socket返回的所有字符串 /// ///包含應答碼的字符串行 private string ReadLine() { while (true) { int iBytes = socketControl.Receive(buffer, buffer.Length, 0); strMsg += GB2312.GetString(buffer, 0, iBytes); if (iBytes < buffer.Length) { break; } } char[] seperator = { ' ' }; string[] mess = strMsg.Split(seperator); if (strMsg.Length > 2) { strMsg = mess[mess.Length - 2]; //seperator[0]是10,換行符是由13和0組成的,分隔後10後面雖沒有字符串, //但也會分配為空字符串給後面(也是最後一個)字符串數組, //所以最後一個mess是沒用的空字符串 //但為什麼不直接取mess[0],因為只有最後一行字符串應答碼與信息之間有空格 } else { strMsg = mess[0]; } if (!strMsg.Substring(3, 1).Equals( ))//返回字符串正確的是以應答碼(如220開頭,後面接一空格,再接問候字符串) { return ReadLine(); } return strMsg; } ////// 發送命令並獲取應答碼和最後一行應答字符串 /// ///命令 private void SendCommand(String strCommand) { Byte[] cmdBytes = GB2312.GetBytes((strCommand + ).ToCharArray()); socketControl.Send(cmdBytes, cmdBytes.Length, 0); ReadReply(); } #endregion } }