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. SourceForge.net Logo

Last updated: July 22, 2003.