C#中的简单FTP库






3.93/5 (10投票s)
C#中FTP协议的完整演练
引言
這是我在 CodeProject 的第一篇文章。在這裡,我將使用我編寫的一個易於使用的程式庫,來說明如何在 C# 中使用 FTP。我使用了命名空間 System.Net
中的類別 FtpWebRequest
和 FtpWebResponse
,它們是密封類別(不能繼承)。
我目前實現了以下 FTP 功能
- 列出檔案、列出目錄
- 上傳、下載檔案
- 建立/刪除目錄和刪除檔案
T-FTP 類別的內部
FtpModeUsePassive
、CurrentDirectory
、FtpServer
、FtpPassword
、FtpUserName
是代表伺服器名稱、FTP 使用者、FTP 密碼以及模式名稱(布林類型)即被動和主動的屬性。
public bool FtpModeUsePassive
{
get;
set;
}
public string CurrentDirectory
{
get;
set;
}
public string FtpServer
{
get;
set;
}
public string FtpUserName
{
get;
set;
}
public string FtpPassword
{
get;
set;
}
刪除檔案/目錄並建立新目錄
我們使用 FTP URL 為特定檔案或目錄建立 FtpWebRequest
類別的實例。例如,如果檔案位於 ftp://2shar.servehttp.com/httpdocs/myfiles/,則程式碼中的相應 URL 將如下所示
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri("ftp://" + FtpServer + serverUri));
接下來,reqFTP.Credentials
屬性採用 NetworkCredential
類別的物件,該物件是通過指定使用者名稱和密碼作為參數的建構函式建立的(我們也可以在 NetworkCredential
的建構函式中指定網域名稱)。
request.Credentials = new NetworkCredential(FtpUserName, FtpPassword);
KeepAlive
屬性指定在執行相應處理後連線是否保持開啟,預設值為 true
。
UseBinary
屬性指定 FTP 操作模式,您可以選擇二進位制或 ASCII 模式。每種模式都有其適用情況,如果您主要處理文字檔案和包含 ASCII 格式文字的文件,可以將該屬性初始化為 false
;如果您需要傳輸媒體檔案、圖片或任何涉及二進位制資料流的 zip 檔案,最好選擇二進位制模式,即將該屬性設定為 true
。
在檔案上傳的情況下,有一個 ContentLength
屬性,必須將其設定為您要上傳的檔案的大小。
FileInfo
類別提供了執行此操作的方法,FileInfo
類別具有 Length
屬性(給出檔案大小)、Name
(給出檔案名稱)、FullName
(檔案的完整路徑)。
FtpWebRequest
的 Method
屬性告訴我們請求的目的(是建立目錄、刪除目錄還是檔案)。
request.Method = WebRequestMethods.Ftp.DeleteFile;
request.Method = WebRequestMethods.Ftp.MakeDirectory;
request.Method = WebRequestMethods.Ftp.RemoveDirectory;
現在我們獲取 FtpWebRequest
的響應,並將其放入 FtpWebResponse
物件中。response.StatusDescription
提供有關 FTP 請求狀態的資訊,可以傳遞給呼叫者。可以使用 try-catch 區塊處理任何例外情況,並將例外情況返回給呼叫者。
public override string FtpMakeDirectory(string serverUri)
{
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri("ftp://" + FtpServer + serverUri));
request.Credentials = new NetworkCredential(FtpUserName, FtpPassword);
request.UsePassive = FtpModeUsePassive;
request.KeepAlive = false;
request.UseBinary = true;
request.Method = WebRequestMethods.Ftp.MakeDirectory;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
response.Close();
return response.StatusDescription.ToString();
}
catch (Exception SomeException)
{
return "error-" + SomeException.Message.ToString();
}
}
// performs the FTP remove directory
public override string FtpRemoveDirectory(string serverUri)
{
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri("ftp://" + FtpServer + serverUri));
request.Credentials = new NetworkCredential(FtpUserName, FtpPassword);
request.UsePassive = FtpModeUsePassive;
request.KeepAlive = false;
request.UseBinary = true;
request.Method = WebRequestMethods.Ftp.RemoveDirectory;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
response.Close();
return response.StatusDescription.ToString();
}
catch (Exception SomeException)
{
return "error-" + SomeException.Message.ToString();
}
}
檔案上傳和下載
當使用者下載檔案時,需要使用 FTP URL 為特定檔案建立 FtpWebRequest
類別的實例(例如,如果檔案位於 ftp://2shar.servehttp.com/httpdocs/myfile.zip,則程式碼中的相應 URL 將如下所示。
request = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + FtpServer + url + fileInf.Name));
接下來,request.Credentials
屬性採用 NetworkCredential
類別的物件,該物件是通過指定使用者名稱和密碼作為參數的建構函式建立的(我們也可以在 NetworkCredential
的建構函式中指定網域名稱)。
request.Credentials = new NetworkCredential(FtpUserName, FtpPassword);
KeepAlive
屬性指定在執行相應處理後連線是否保持開啟,預設值為 true
。
UseBinary
屬性指定 FTP 操作模式,您可以選擇二進位制或 ASCII 模式。每種模式都有其適用情況,如果您主要處理文字檔案和包含 ASCII 格式文字的文件,可以將該屬性初始化為 false
;如果您需要傳輸媒體檔案、圖片或任何涉及二進位制資料流的 zip 檔案,最好選擇二進位制模式,即將該屬性設定為 true
。
在檔案上傳的情況下,有一個 ContentLength
屬性,必須將其設定為您要上傳的檔案的大小。
FileInfo
類別提供了執行此操作的方法,FileInfo
類別具有 Length
屬性(給出檔案大小)、Name
(給出檔案名稱)、FullName
(檔案的完整路徑)。
FtpWebRequest
的 Method
屬性告訴我們請求的目的(是上傳、下載還是刪除等)。
request.Method = WebRequestMethods.Ftp.DownloadFile;
在下載時,我們使用指定的路徑、建立模式和寫入權限來初始化 FileStream
類別的新實例。
FileStream fileStreamObject = new FileStream(downloadPath + fileInf.Name, FileMode.Create, FileAccess.Write);
我們可以通過將 FtpWebRequest.Method
設定為 WebRequestMethods.Ftp.GetFileSize
來獲取下載檔案的大小。FtpFileSize()
可以完成這項工作。對所建立請求的響應將提供檔案的大小。
通過將大小/100 作為位元組緩衝區的大小,我們可以從響應流中讀取,這有助於顯示下載狀態和時間。
我們檢查 downloadFile
事件是否不為 null,以避免因事件未由使用者初始化而導致的運行時非預期行為。
long tempLength = FtpFileSize("ftp://" + FtpServer + fileInf.ToString());
byte[] bufferByte = new byte[tempLength / 100];
int contentLength;
contentLength = responseStream.Read(bufferByte, 0, bufferByte.Length);
long tempLength1 = tempLength;
while (contentLength != 0)
{
fileStreamObject.Write(bufferByte, 0, contentLength);
contentLength = responseStream.Read(bufferByte, 0, bufferByte.Length);
tempLength -= contentLength;
if (tempLength > 0)
{
if (downloadFile != null)
{
downloadFile(tempLength1, tempLength);
}
}
}
然後,我們可以從響應流中讀取,並將讀取的位元組寫入 filestream
物件。
contentLength = responseStream.Read(bufferByte, 0, bufferByte.Length);
fileStreamObject.Write(bufferByte, 0, contentLength);
一旦我們完全從響應流中讀取完畢,我們將關閉 filestream
物件,並返回響應物件的狀態,以告知呼叫者其請求的狀態(即檔案是否已下載)。
fileStreamObject.Close();
responseStream.Close();
return response.StatusDescription.ToString();
public override event DisplayDownloadDelegate downloadFile;
public override event DisplayUploadDelegate uploadFile;
public override event CollectFilesDelegate displayCollectFiles;
public override event CollectDirectoryDelegate displayCollectDirectory;
//we have created the events of corresponding delegate type so that user can just subcribe
// to the event and display the result in the way they intend to.
//we have overridden the event because we have used a top abstract class and are using the object
//the abstract class and instantiating the object using subclasses.
上述程式碼中給出了上傳和下載的事件及委派。這種方法用於實現訂閱者-發布者設計模式,其中 tftp.dll 發布了一組事件,分別為 uploadFile
和 downloadFile
,它們對應於委派類型 DisplayUploadDelegate
和 DisplayDownloadDelegate
。
現在,使用 DLL 檔案的人可以通過使用一個函數來訂閱事件,該函數也必須是 DisplayUploadDelegate
和 DisplayDownloadDelegate
委派類型。
當事件引發時,使用者定義的這些函數將被呼叫。如果您查看下載的程式碼,您會注意到我們在 FtpFileDownload
函數 downloadFile(len1,len)
中,在從響應流中讀取每一組位元組後引發了事件。這樣,我們就呼叫了使用 DLL 的人員編寫的訂閱者函數。
處理下載(FtpFileDownload
)和上傳(FtpFileUpload
)的函數如下所示。
//FTP file Upload
public override string FtpFileUpload(string fileName, string url)
{
try
{
FileInfo fileInf = new FileInfo(fileName);
string uri = "ftp://" + FtpServer + "/" + url + fileInf.Name;
FtpWebRequest request;
request = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + FtpServer + url + fileInf.Name));
request.Credentials = new NetworkCredential(FtpUserName, FtpPassword);
request.UsePassive = FtpModeUsePassive;
request.KeepAlive = false;
request.Method = WebRequestMethods.Ftp.UploadFile;
request.UseBinary = true;
request.ContentLength = fileInf.Length;
long buffLength = fileInf.Length / 100;
byte[] bufferByte = new byte[buffLength];
int contentLength;
FileStream fileStreamObject = fileInf.OpenRead();
FtpWebResponse resp = (FtpWebResponse)request.GetResponse();
Stream streamObject = request.GetRequestStream();
contentLength = fileStreamObject.Read(bufferByte, 0, (int)buffLength);
long tempLength = fileStreamObject.Length;
while (contentLength != 0)
{
streamObject.Write(bufferByte, 0, contentLength);
contentLength = fileStreamObject.Read(bufferByte, 0, (int)buffLength);
tempLength -= contentLength;
if (tempLength > 0)
{
if (uploadFile != null)
{
uploadFile(fileStreamObject.Length, tempLength);
}
}
}
streamObject.Close();
fileStreamObject.Close();
return resp.StatusDescription.ToString();
}
catch (Exception SomeException)
{
return SomeException.Message.ToString();
}
}
//Get size of the file
public override long FtpFileSize(string url)
{
FtpWebRequest reqSize = (FtpWebRequest)FtpWebRequest.Create(new Uri(url));
reqSize.Credentials = new NetworkCredential(FtpUserName, FtpPassword);
reqSize.Method = WebRequestMethods.Ftp.GetFileSize;
reqSize.UseBinary = true;
reqSize.UsePassive = FtpModeUsePassive;
FtpWebResponse respSize = (FtpWebResponse)reqSize.GetResponse();
respSize = (FtpWebResponse)reqSize.GetResponse();
long size = respSize.ContentLength;
respSize.Close();
return size;
}
//Ftp file download
public override string FtpFileDownload(string fileUrl, string downloadPath)
{
try
{
FileInfo fileInf = new FileInfo(fileUrl);
string uri = "ftp://" + FtpServer + "/httpdocs/" + fileInf.Name;
FtpWebRequest request;
request = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + FtpServer + fileInf.ToString()));
request.Credentials = new NetworkCredential(FtpUserName, FtpPassword);
request.UsePassive = FtpModeUsePassive;
request.UseBinary = true;
request.KeepAlive = false;
request.Method = WebRequestMethods.Ftp.DownloadFile;
FtpWebResponse response = (FtpWebResponse) request.GetResponse();
Stream responseStream = response.GetResponseStream();
FileStream fileStreamObject = new FileStream(downloadPath + fileInf.Name, FileMode.Create, FileAccess.Write);
long tempLength = FtpFileSize("ftp://" + FtpServer + fileInf.ToString());
byte[] bufferByte = new byte[tempLength / 100];
int contentLength;
contentLength = responseStream.Read(bufferByte, 0, bufferByte.Length);
long tempLength1 = tempLength;
while (contentLength != 0)
{
fileStreamObject.Write(bufferByte, 0, contentLength);
contentLength = responseStream.Read(bufferByte, 0, bufferByte.Length);
tempLength -= contentLength;
if (tempLength > 0)
{
if (downloadFile != null)
{
downloadFile(tempLength1, tempLength);
}
}
}
fileStreamObject.Close();
responseStream.Close();
return response.StatusDescription.ToString();
}
catch (Exception SomeException)
{
return SomeException.Message.ToString();
}
}
檔案和目錄列表
現在我將解釋目錄檢索。首先,我們需要使用 FTP URL 為特定目錄建立 FtpWebRequest
類別的實例(例如,如果目錄是 ftp://2shar.servehttp.com/httpdocs/,則請求的相應 URL 將如下所示。
request = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + FtpServer + url));
接下來,reqFTP.Credentials
屬性採用 NetworkCredential
類別的物件,該物件是通過指定使用者名稱和密碼作為參數的建構函式建立的(我們也可以在 NetworkCredential
的建構函式中指定網域名稱)。
request.Credentials = new NetworkCredential(FtpUserName, FtpPassword);
KeepAlive
屬性指定在執行相應處理後連線是否保持開啟,預設值為 true
。
UseBinary
屬性指定 FTP 操作模式,您可以選擇二進位制或 ASCII 模式。每種模式都有其適用情況,如果您主要處理文字檔案和包含 ASCII 格式文字的文件,可以將該屬性初始化為 false
;如果您需要傳輸媒體檔案、圖片或任何涉及二進位制資料流的 zip 檔案,最好選擇二進位制模式,即將該屬性設定為 true
。
FileInfo
類別提供了執行此操作的方法,FileInfo
類別具有 Length
屬性(給出檔案大小)、Name
(給出檔案名稱)、FullName
(檔案的完整路徑)。
FtpWebRequest
的 Method
屬性告訴我們請求的目的(是上傳、下載、刪除還是列出檔案或目錄等)。
我們使用 WebRequestMethods.Ftp.ListDirectoryDetails
來顯示與每個檔案關聯的建立日期和大小的詳細資訊。如果只需要顯示檔案名稱,則可以使用 WebRequestMethods.Ftp.ListDirectory
。
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
然後,我們獲取 FTP 請求的響應,並將其儲存在 FtpWebResponse
物件(response
)中,獲取響應物件的流,並藉助 StreamReader
物件讀取流。程式碼如下所示。
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader readerObject = new StreamReader(responseStream);
我們可以通過使用字串類別的方法,例如 String.IndexOf(string value,int startindex)
和 String.subString(int startindex,int length)
,仔細地提取 StreamReader
類別讀取的字串中的目錄名稱和目錄建立日期。
if (processString.IndexOf("<DIR>", 0) != -1)
{
string processedString = RemoveWhiteSpaces(processString);
dirdate = processedString.Substring(0, processedString.IndexOf("<DIR>", 0));
dirname = processedString.Substring(processedString.IndexOf("<DIR>", 0) + 5, processedString.Length - (processedString.IndexOf("<DIR>", 0) + 5));
listDirectoryCollection.Add(dirname, dirdate);
displayCollectDirectory(dirname, dirdate);
}
現在,我們可以通過返回響應物件的狀態來獲取操作狀態。
return response.StatusDescription.ToString();
處理列出目錄(FtpListDirectories
)和列出檔案(FtpListFiles
)的函數如下所示。
// resolving and formatting display of files
public override string[] ResolveFiles(string filesString)
{
string resultString = string.Empty;
char[] arrayOfCharacters = filesString.ToCharArray();
bool flags = false;
foreach (char singleCharacter in arrayOfCharacters)
{
if (singleCharacter == ' ')
{
if (flags == false)
{
resultString = resultString + "#";
}
flags = true;
}
else
{
resultString = resultString + singleCharacter;
flags = false;
}
}
char[] seperatorCharacter = { '#' };
string[] returnStringArray = resultString.Split(seperatorCharacter);
return returnStringArray;
}
//remove white spaces
public override string RemoveWhiteSpaces(string processString)
{
string resultString = string.Empty;
char[] arrayOfCharacters = processString.ToCharArray();
foreach (char singleCharacter in arrayOfCharacters)
{
if (singleCharacter != ' ')
{
resultString = resultString + singleCharacter.ToString();
}
}
return resultString;
}
//perform listing of directories on server
public override string FtpListDirectories(string url)
{
listDirectoryCollection = new Dictionary<string, string>(100000);
try
{
string uri = FtpServer + url;
FtpWebRequest request;
request = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + FtpServer + url));
request.Credentials = new NetworkCredential(FtpUserName, FtpPassword);
request.UsePassive = FtpModeUsePassive;
request.KeepAlive = true;
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
request.UseBinary = true;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
string processString;
string dirname, dirdate;
processString = reader.ReadLine();
while (processString != null)
{
if (processString.IndexOf("<DIR>", 0) != -1)
{
string processedString = RemoveWhiteSpaces(processString);
dirdate = processedString.Substring(0, processedString.IndexOf("<DIR>", 0));
dirname = processedString.Substring(processedString.IndexOf("<DIR>", 0) + 5, processedString.Length - (processedString.IndexOf("<DIR>", 0) + 5));
listDirectoryCollection.Add(dirname, dirdate);
displayCollectDirectory(dirname, dirdate);
}
else
{
}
processString = reader.ReadLine();
}
reader.Close();
response.Close();
return "ok";
}
catch (Exception SomeException)
{
return SomeException.Message.ToString();
}
}
// perform file listing on server
public override string FtpListFiles(string url)
{
listFileCollection = new Dictionary<string, string>(100000);
try
{
string uri = "ftp://" + FtpServer + url;
FtpWebRequest request;
request = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + FtpServer + url));
request.Credentials = new NetworkCredential(FtpUserName, FtpPassword);
request.KeepAlive = true;
request.UsePassive = FtpModeUsePassive;
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
request.UseBinary = true;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader readerObject = new StreamReader(responseStream);
string processString;
string dirname, dirdate;
processString = readerObject.ReadLine();
while (processString != null)
{
if (processString.IndexOf("<DIR>", 0) != -1)
{
string processedString = RemoveWhiteSpaces(processString);
dirdate = processedString.Substring(0, processedString.IndexOf("<DIR>", 0));
dirname = processedString.Substring(processedString.IndexOf("<DIR>", 0) + 5, processedString.Length - (processedString.IndexOf("<DIR>", 0) + 5));
}
else
{
string[] processedString = ResolveFiles(processString);
listFileCollection.Add(processedString[3].ToString(), (Int32.Parse(processedString[2].ToString()) / 1024).ToString());
displayCollectFiles(processedString[3].ToString(), (Int32.Parse(processedString[2].ToString()) / 1024).ToString(), processedString[0] + "-" + processedString[1]);
}
processString = readerObject.ReadLine();
}
readerObject.Close();
response.Close();
return response.StatusDescription.ToString();
}
catch (Exception SomeException)
{
return SomeException.Message.ToString();
}
}
在您的專案中使用 T-FTP 程式庫
在引言部分,我已經展示了 tftp 程式庫的內部構造和工作原理。現在我將解釋如何將其整合到您的專案中。
属性
屬性名稱 | 語義 | 資料類型 |
FtpUserName | 代表 ftp 使用者名稱 | 字串 |
FtpServer | 代表 ftp 地址 | 字串 |
| 代表 ftp 使用者密碼 | 字串 |
| 在兩種模式之間選擇 | bool |
示例
TusharFtp.FtpClass ftpObject = new TusharFtp.FtpHelperClass();
ftpObject.FtpServer = servers;
ftpObject.FtpUserName = users;
ftpObject.FtpPassword = pass;
ftpObject.FtpModeUsePassive = true;
1. 上傳(包含上傳狀態)
如果 uploadme
是訂閱 upload_file
事件的函數名稱。
變數 a
和 b
分別代表檔案的總大小(位元組)和待下載/上傳的大小。
//
static void UploadMe(long totalLength, long currentLength)
{
Console.WriteLine(currentLength + " out of " + totalLength +"has been left to downloaded so far");
}
ftpObject.uploadFile += new tftp.tftp.DisplayUploadDelegate(UploadMe);
//hooking up the event 'uploadFile' with your 'UploadMe' function of delegate type 'DisplayUploadDelegate'
Console.WriteLine( ftpObject.FtpFileUpload("e:\\splits.zip","/httpdocs/"));
//calling the FtpFileUpload function with parameters path of the file,the url on server where it has to be uploaded
//
下載函數也類似。
2. 列出目錄
如果 FtpListDirectories
是訂閱 displayCollectDirectory
事件的函數名稱。
FtpListDirectories
是 DLL 中用於獲取目錄列表的函數,函數參數代表目錄名稱和目錄的建立日期。
//
static void ListDirectories(string directoryName,string directoryCreateDate)
{
Console.WriteLine("directory name= "+directoryName+" directory creation date= "+directoryCreateDate);
}
ftpObject.displayCollectDirectory += new TusharFtp.CollectDirectoryDelegate(ListDirectories);
//hooking up the event 'displayCollectDirectory' with your
//'ListDirectories' function of type delegate 'CollectDirectoryDelegate'
ftpObject.FtpListDirectories("/httpdocs/");
//listing the directories in url ftp://website.com/httpdocs
//
類似地,對於列出檔案,我們可以使用 FtpListFiles()
函數。
3. 列出檔案
如果 FtpListFiles
是訂閱 displayCollectFiles
事件的函數名稱。
FtpListFiles
是 DLL 中用於獲取檔案列表的函數,函數參數代表檔案名稱、檔案大小和檔案的建立日期。
//
static void ListFiles(string fileName,string fileSize,string fileCreateDate)
{
Console.WriteLine("file name= "+fileName+" file size= "+fileSize+" file creation date "+fileCreateDate);
}
ftpObject.displayCollectFiles += new TusharFtp.CollectFilesDelegate(listdir);
//hooking up the event 'displayCollectFiles' with
//your 'ListFiles' function of type delegate 'CollectFilesDelegate'
ftpObject.FtpListFiles("/httpdocs/");
//listing the files in url ftp://website.com/httpdocs
4. 建立目錄、刪除目錄和刪除檔案
這些函數具有字串返回類型,用於告知操作狀態。FtpMakeDirectory
、FtpRemoveDirectory
、FtpDeleteFile
分別代表建立目錄、刪除目錄和刪除檔案的三個函數。
//
string makeDirectoryStatus = ftpObject.FtpMakeDirectory("httpdocs/tftp");
string removeStatus = ftpObject.FtpRemoveDirectory("httpdocs/tftp");
string deleteStatus=ftpObject.FtpDeleteFile("httpdocs/splits.zip");
//
值得關注的點
感謝閱讀。您可以在 MSDN 中瞭解更多關於 FTPWebRequest
類別的知識,以及在 MSDN 中瞭解 FTPWebResponse
類別。