1 串連遠程伺服器
procedure Connect(AAutoLogin: boolean; const ATimeout: Integer);
2 改變目錄
procedure ChangeDir(const ADirName: string);
3 下載
procedure Get(const ASourceFile: string; ADest: TStream; AResume: Boolean); overload;
procedure Get(const ASourceFile: string; const ADestFile: string; const ACanOverwrite: boolean; AResume: Boolean); overload;
4 上傳
procedure Put(const ASource: TStream; const ADestFile: string; const AAppend: boolean); overload;
procedure Put(const ASourceFile: string; const ADestFile: string; const AAppend: boolean); overload;
5 刪除
procedure Delete(const AFilename: string);
判斷是否串連
if IdFTP1.Connected then
begin
...........
end;
引用別人一下,做為自己以後筆記
現在很多應用都需要上傳與下載大型檔案,通過HTTP方式上傳大檔案有一定的局限性。幸好FTP作為一個非常老而且非常成熟的協議可以高效穩定地完成大檔案的上傳下載,並且可以完美地實現續傳。就拿我寫的電影伺服器管理端程式來說,各種方案比較後,發現使用FTP可以完美地實現要求。但是要通過WinSocket庫實現FTP比較麻煩,幸好有Indy--一個封裝了大多數網路通訊協定的組件包。
通過Indy,程式設計人員可以通過阻塞方式進行編程,可以拋開蹩腳的Winsocket非同步模式,採用與Unix系統上等同的阻塞編程模式進行。這樣,程式員就可以很好的處理常式的運行流程。
下面,我們進入到Indy的TIdFtp世界。
1.控制項的說明
使用Indy 9中的TIdFtp控制項可以實現通過FTP方式進行檔案的上傳與下載。
2.控制項的具體使用
(1)控制項屬性設定
預設屬性即可,與伺服器串連直接相關的屬性如主機名稱與使用者等在建立串連時進行設定。需要設定的是RecvBufferSize和SendBufferSize兩屬性的值。另外需要根據要傳輸的檔案類型指定TransferType屬性,而其他屬性按預設值設定即可。
RecvBufferSize說明(預設值為8192位元組):該屬性為整型變數,用於指定串連所用的接受緩衝區大小。
SendBufferSize說明(預設值為32768位元組):該屬性也為整型變數,用於指定串連所用的發送緩衝區的最大值。該屬性在WriteStream方法中時,可用於TStream指定要發送內容的塊數。如果要發送的內容大於本屬性值,則發送內容被分為多個塊發送。
TransferType說明(預設值為ftBinary):該屬性為TIdFTPTransferType型變數。用於指定傳輸內容是二進位檔案(ftBinary )還是ASCII檔案(ftASCII)。應用程式需要使用二進位方式傳輸可執行檔、壓縮檔和多媒體檔案等;而使用ASCII方式傳輸文本或超文本等文本型資料。
(2)控制項的事件響應
OnDisconnected響應:TNotifyEvent類,用於響應斷開(disconnect)事件。當Disconnect方法被調用用來關閉Socket的時候,觸發該響應。應用程式必須指定該事件響應的過程,以便對該斷開事件進行相應。
OnStatus響應:TIdStatusEvent類。該響應在當前串連的狀態變化時被觸發。該事件可由DoStatus方法觸發並提供給事件控制器屬性。axStatus是當前串連的TIdStatus值;aaArgs是一個可選的參數用于格式化函數,它將用於構造表現當前串連狀態的簡訊。
OnWork響應:OnWord是TWorkEvent類事件的響應控制器。OnWork用於關聯DoWork方法當緩衝區讀寫操作被調用時通知Indy組件和類。它一般被用於控制進度條和視窗元素的更新。AWorkMode表示當前操作的模式,其中:wmRead-組件正在讀取資料;wmWrite-組件正在發送資料。AWorkCount指示當前操作的位元組計數。
OnWorkBegin響應:TWorkBeginEvent類。當緩衝區讀寫操作初始化時,該事件關聯BeginWork方法用於通知Indy組件和類。它一般被用於控制進度條和視窗元素的更新。AWorkMode表示當前操作的模式,其中:wmRead-組件正在讀取資料;wmWrite-組件正在發送資料。AWorkCountMax用於指示發送到OnWorkBegin事件的操作的最大位元組數,0值代表未知。
OnWorkEnd響應:TWorkEndEvent類。當緩衝區讀寫操作終止時,該事件關聯EndWork方法用於通知Indy組件和類。AWorkMode表示當前操作的模式,其中:wmRead-組件正在讀取資料;wmWrite-組件正在發送資料。AWorkCount表示操作的位元組數。
在事件響應中,主要通過上述五種事件響應來控製程序。在一般情況下,在OnDisconnected中設定串連斷開的介面通知;在OnStatus中設定當前操作的狀態;在OnWork中實現傳輸中狀態條和其他參數的顯示;而在OnWorkBegin和OnWorkEnd中分別設定開始傳輸和傳輸結束時的介面。
(3)串連遠程伺服器
完成了設定控制項屬性和實現了控制項的事件響應後,就可以與伺服器進行互動和傳輸了。在串連之前,應首先判斷IdFtp是否處於串連狀態,如果Connected為False,則通過介面控制項或其他方式指定與伺服器串連相關的一些TCP類屬性的設定,分別是:Host(主機名稱):String、Username(使用者名稱):String、Password(密碼):String,也可以指定Port(連接埠)。之後調用Connect方法串連遠程伺服器,如果無異常出現則串連成功建立。
過程說明:procedure Connect(AAutoLogin: boolean; const ATimeout: Integer);
該過程串連遠程FTP伺服器
屬性:AAutoLogin: boolean = True
串連後自動登入,該參數預設為True。
const ATimeout: Integer = IdTimeoutDefault
逾時時間,單位:秒。
範例程式碼:
if IdFTP1.Connected then try
if TransferrignData then IdFTP1.Abort;
IdFTP1.Quit;
finally
end
else with IdFTP1 do try
Username := UserIDEdit.Text;
Password := PasswordEdit.Text;
Host := FtpServerEdit.Text;
Connect;
ChangeDir(CurrentDirEdit.Text);
finally
end;
(4)改變目錄
串連建立後,可以改變當前FTP會話所在的目錄。對於已知絕對路徑的情況下,可以直接調用ChangeDir(const ADirName: string)方法來轉換目錄,ADirName表示伺服器上的檔案系統目錄,另外還可以調用ChangeDirUp回到上級目錄。
如果未知路徑,則可以通過List(ADest: TStrings; const ASpecifier: string; const ADetails: boolean)過程擷取遠程伺服器的目前的目錄結構,此時必須設定TransferType為ftASCII(ASCII模式),其中:ADest儲存目前的目錄結構,可以在後續程式中調用該列表。另外可以通過RetrieveCurrentDir方法擷取目前的目錄名。
過程說明:
procedure ChangeDir(const ADirName: string);
改變工作目錄
屬性
const ADirName: string
遠程伺服器的目錄描述
說明:該過程實際上是實現了FTP CWD命令。
procedure ChangeDirUp;
到上一級目錄
function RetrieveCurrentDir: string;
該函數返回目前的目錄名
procedure List(ADest: TStrings; const ASpecifier: string; const ADetails: boolean);
列出目前的目錄所有檔案和子目錄及其屬性
參數:
ADest: TStrings
儲存檔案及子目錄的返回結果
const ASpecifier: string =
檔案掩碼,用於列出合格檔案
const ADetails: boolean = true
包含檔案和子目錄屬性
property DirectoryListing: TIdFTPListItems;
返迴文件及目錄結構的列表
範例程式碼:
LS := TStringList.Create;
try
IdFTP1.ChangeDir(DirName);
IdFTP1.TransferType := ftASCII;
CurrentDirEdit.Text := IdFTP1.RetrieveCurrentDir;
DirectoryListBox.Items.Clear;
IdFTP1.List(LS);
DirectoryListBox.Items.Assign(LS);
if DirectoryListBox.Items.Count > 0 then
if AnsiPos(total, DirectoryListBox.Items[0]) > 0 then DirectoryListBox.Items.Delete(0);
finally
LS.Free;
end;
(5)下載的實現
在下載之前,必須查看DirectoryListing.Items[sCurrFile].ItemType是否為檔案,如返回為ditDirectory則代表當前檔案名稱為目錄,不能下載,必須導向到檔案才可。如為檔案,則可以進行下載。在下載前,設定傳輸的類型為二進位檔案,並且指定本地要儲存的路徑。通過調用Get方法,實現檔案的下載。下載過程較慢,可以考慮將其放到線程中實現。
過程說明:
procedure Get(const ASourceFile: string; ADest: TStream; AResume: Boolean); overload;
procedure Get(const ASourceFile: string; const ADestFile: string; const ACanOverwrite: boolean; AResume: Boolean); overload;
從遠程伺服器上擷取檔案。
屬性說明:
const ASourceFile: string
遠程伺服器上的源檔案名稱
const ADestFile: string
儲存到客戶機上的檔案名稱
const ACanOverwrite: boolean = false
重寫同名檔案
AResume: Boolean = false
是否進行斷點續傳
範例程式碼:
SaveDialog1.FileName := Name;
if SaveDialog1.Execute then begin
SetFunctionButtons(false);
IdFTP1.TransferType := ftBinary;
BytesToTransfer := IdFTP1.Size(Name);
if FileExists(Name) then begin
case MessageDlg(File aready exists. Do you want to resume the download operation?,
mtConfirmation, mbYesNoCancel, 0) of
mrYes: begin
BytesToTransfer := BytesToTransfer - FileSizeByName(Name);
IdFTP1.Get(Name, SaveDialog1.FileName, false, true);
end;
mrNo: begin
IdFTP1.Get(Name, SaveDialog1.FileName, true);
end;
mrCancel: begin
exit;
end;
end;
end
else begin
IdFTP1.Get(Name, SaveDialog1.FileName, false);
end;
(6)上傳的實現
上傳的實現與下載類似,通過put方法即可。
過程說明:
procedure Put(const ASource: TStream; const ADestFile: string; const AAppend: boolean); overload;
procedure Put(const ASourceFile: string; const ADestFile: string; const AAppend: boolean); overload;
上傳檔案至伺服器
屬性說明:
const ASourceFile: string
將要被上傳的檔案
const ADestFile: string =
伺服器上的目標檔案名
const AAppend: boolean = false
是否繼續上傳
程式碼範例:
if IdFTP1.Connected then begin
if UploadOpenDialog1.Execute then try
IdFTP1.TransferType := ftBinary;
IdFTP1.Put(UploadOpenDialog1.FileName, ExtractFileName(UploadOpenDialog1.FileName));
//可以在此添加改變目錄的代碼;
finally
//完成清除工作
end;
end;
(7)刪除的實現
刪除檔案使用Delete方法,該方法刪除指定的檔案,刪除對象必須為檔案。如果要刪除目錄則使用RemoveDir方法。
過程說明:
procedure Delete(const AFilename: string);
刪除檔案
procedure RemoveDir(const ADirName: string);
刪除檔案夾,根據不同的伺服器刪除檔案夾有不同的要求。有些伺服器不允許刪除非空檔案夾,程式員需要添加清空目錄的代碼。
上述兩個過程的參數均為目標名稱
程式碼範例:
if not IdFTP1.Connected then exit;
Name := IdFTP1.DirectoryListing.Items[iCurrSelect].FileName;
if IdFTP1.DirectoryListing.Items[iCurrSelect].ItemType = ditDirectory then try
idftp1.RemoveDir(Name);
finally
end
else
try
idftp1.Delete(Name);
finally
end;
(8)後退的實現
後退在實際上是目錄操作的一種,可以簡單的改變目前的目錄為..來實現,也可以通過回到上級目錄來實現。
(9)取消的實現
在IdFtp的傳輸過程中,可以隨時使用abort方法取消當前操作。可以的OnWork事件的實現中來確定何時取消操作。
程式碼範例:
//取消按鈕的OnClick響應
procedure TMainForm.AbortButtonClick(Sender: TObject);
begin
AbortTransfer := true;
end;
//IdFTP的OnWork事件響應
procedure TMainForm.IdFTP1Work(Sender: TObject; AWorkMode: TWorkMode;
const AWorkCount: Integer);
begin
...
if AbortTransfer then IdFTP1.Abort;
AbortTransfer := false;
end;
(10)斷點續傳的實現
斷點續傳就是在上傳或下載過程開始時,判斷已經傳輸過的檔案是否上傳輸完畢,如果傳輸沒有成功完成,則在上次中斷處繼續進行傳輸工作。實現該功能需要兩個重要的操作,首先是判斷檔案的大小資訊,其次是在傳輸過程Get和Put中指定上傳的行為。
判斷伺服器上檔案的大小使用函數Size(FileName)。在下載過程中,比較本地檔案和遠程檔案的資訊,然後在Get中指定AResume := True即可。而上傳也一樣,指定Put的AAppend := True就可以了。
在前面我們講過,Indy的網路操作大部分是阻塞模式的,TIdFtp也不例外。這樣在上述各個操作運行過程的時候使用者介面被暫時凍結,必須要等待調用返回才能繼續使用者操作介面響應。所以在實際編程中,需要使用多線程的方式來保證戶介面的響應。Windows系統可以使用CreateThread系統調用來建立線程,但是在使用的時候需要開發人員做很多額外的工作來保證線程的同步等問題。而Indy中也包含了實現多線程的控制項TIdThreadComponent,相對比之下該控制項實現多線程時更加方便,也更容易控制。我將在後續的文章裡為大家介紹TIdThreadCOmponent的使用方法