|
|
|
|
FTP: Automating File Transfers
This article is the second in a series about the TApdFtpClient component. The first article demonstrated how to use the OnFtpStatus event of the TApdFtpClient to easily navigate through a remote directory tree (see that tech tip). Continuing in the same vein, this article presents an example project that illustrates how to use the OnFtpStatus event to download multiple files automatically.
As in the previous example project, you select the remote directories by double-clicking on the directory name in the list box. In this example we will automatically download all the files contained in the selected directory.
The following figure shows the form of the example at run-time.
You can build from the previous example or start a new project by dropping a TApdFtpClient, TListBox, and a couple of TButton’s onto the main form of a new application. You can set the URL, UserName, and Password properties of the TApdFtpClient component at design time via the object inspector, or set them at run time from TEdit controls as I’ve done with this example. At any rate, these need to be set prior to attempting to login to an FTP server. In addition, I’ve included an edit control to specify the name of the local directory where the files will be downloaded.
The following are event handlers I’ve defined for the OnClick event for the Login and Logout buttons:
Delphi:
procedure TForm1.btnLoginClick(Sender: TObject); begin with ApdFtpClient1 do begin ServerAddress := edtServer.Text; UserName := edtUser.Text; Password := edtPassword.Text; Login; end; end;
procedure TForm1.btnLogoutClick(Sender: TObject); begin ApdFtpClient1.Logout; end;
C++Builder:
void __fastcall TForm1::btnLoginClick(TObject *Sender) { ApdFtpClient1->ServerAddress = edtURL->Text; ApdFtpClient1->UserName = edtUsername->Text; ApdFtpClient1->Password = edtPassword->Text; ApdFtpClient1->Login(); }
void __fastcall TForm1::btnLogoutClick(TObject *Sender) { ApdFtpClient1->Logout(); }
Remaining event handlers and methods use the following global variables:
Delphi:
var DownloadList : TStringList; { list files to be transferred } CurrentFile : string; { file currently being transferred } SelectedDir : string; { current working directory }
C++Builder:
TStringList *DownloadList; // list files to be transferred AnsiString CurrentFile; // file currently being transferred AnsiString SelectedDir; // current working directory
Once successfully logged in, display the contents of the server’s current working directory in the list box, and start downloading all the files in list. Also, we’ll want to refresh the list and download each time we move to another directory. Again, use the OnFtpStatus event to drive the process:
Delphi:
procedure TForm1.ApdFtpClient1FtpStatus(Sender: TObject; StatusCode: TFtpStatusCode; InfoText: PChar); begin case StatusCode of scLogout : { cleanup lists } begin Caption := 'Logged out'; lbxFiles.Clear; DownloadList.Clear; end; scLogin : { request name of CWD } begin Caption := 'Logged in'; ApdFtpClient1.CurrentDir; end; scCurrentDir : { request a list of files in CWD } ApdFtpClient1.ListDir('', False); scComplete : { CWD changed, request its name } ApdFtpClient1.CurrentDir; scDataAvail : { file list data, start downloading } begin lbxFiles.Items.Text := StrPas(InfoText); DownloadList.Assign(lbxFiles.Items); lbxFiles.Items.Insert(0, '..'); lbxFiles.Items.Insert(0, '.'); RetrieveNext; end; scProgress : { display download progress } Caption := CurrentFile + ' ' + IntToStr(ApdFtpClient1.BytesTransferred); scTransferOK : { file downloaded, download next file } begin if DownloadList.Count > 0 then DownloadList.Delete(0); RetrieveNext; end; end; end;
procedure TForm1.RetrieveNext; begin if (DownloadList.Count > 0) then begin CurrentFile := DownloadList[0]; Caption := DownloadList[0]; ApdFtpClient1.Retrieve(DownloadList[0], edtLocalDir.Text + '\' + DownloadList[0],rmReplace); end; end;
C++Builder:
void __fastcall TForm1::ApdFtpClient1FtpStatus(TObject *Sender, TFtpStatusCode StatusCode, PChar InfoText) { switch (StatusCode) { case scLogout : // cleanup lists Caption = "Logged out"; lbxFiles->Clear(); DownloadList->Clear(); break; case scLogin : // request name of CWD Caption = "Logged in"; ApdFtpClient1->CurrentDir(); break; case scCurrentDir : // request a list of files in CWD ApdFtpClient1->ListDir("", False); break; case scComplete : // CWD changed, request its name ApdFtpClient1->CurrentDir(); break; case scDataAvail : // file list data, download 1st one lbxFiles->Items->Text = StrPas(InfoText); DownloadList->Assign(lbxFiles->Items); lbxFiles->Items->Insert(0, ".."); lbxFiles->Items->Insert(0, "."); RetrieveNext(); break; case scProgress : // display download progress Caption = CurrentFile + " " + IntToStr(ApdFtpClient1->BytesTransferred); break; case scTransferOK : // file downloaded, download the next one if (DownloadList->Count > 0) DownloadList->Delete(0); RetrieveNext(); break; } } //-------------------------------------------------------------- void __fastcall TForm1::RetrieveNext(void) { if (DownloadList->Count > 0) { CurrentFile = DownloadList->Strings[0]; Caption = DownloadList->Strings[0]; ApdFtpClient1->Retrieve(DownloadList->Strings[0], edtLocalDir->Text + "\\" + DownloadList->Strings[0],rmReplace); } }
To handle the double-click selection, define the following TMemo event handlers:
Delphi:
procedure TForm1.lbxFilesMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var i : Integer; begin i := lbxFiles.ItemAtPos(Point(X, Y), True); if (i > -1) then SelectedDir := lbxFiles.Items[i]; end;
procedure TForm1.lbxCurrentDirDblClick(Sender: TObject); begin ApdFtpClient1.ChangeDir(SelectedDir); end;
C++Builder:
void __fastcall TForm1::lbxFilesMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { int i = lbxFiles->ItemAtPos(Point(X, Y), true); if (i > -1) SelectedDir = lbxFiles->Items->Strings[i]; } //-------------------------------------------------------------- void __fastcall TForm1::lbxFilesDblClick(TObject *Sender) { ApdFtpClient1->ChangeDir(SelectedDir); }
Lastly, some items in the directory list are not files and the server will respond with an error when we try to download them. Here, we’ll use the OnFtpError event to move on to the next item in the list:
Delphi:
procedure TForm1.ApdFtpClient1FtpError(Sender: TObject; ErrorCode: Integer; ErrorText: PChar); begin if (DownloadList.Count > 0) then DownloadList.Delete(0); RetrieveNext(); end;
C++Builder:
void __fastcall TForm1::ApdFtpClient1FtpError(TObject *Sender, int ErrorCode, PChar ErrorText) { if (DownloadList->Count > 0) DownloadList->Delete(0); RetrieveNext(); }
OK, now compile and run it to start downloading all those files you’ve been putting off. Hopefully, by now you get an idea of how to use the OnFtpStatus event to drive a sequence of FTP related tasks. |
This site is not affiliated, endorsed, or otherwise associated with the
entity formerly known as
TurboPower Software. The owners and maintainers of Aprozilla.com were merely
meager employees of the aforementioned organization, providing this site out of
the pure goodness of their collective hearts.
|