Artigo Clube Delphi Edição 11 - O objeto TNMFTP

Artigo da Revista Clube Delphi Edição 11.

Esse artigo faz parte da revista Clube Delphi edição 11. Clique aqui para ler todos os artigos desta edição

Capa Revista

Atenção: por essa edição ser muito antiga não há arquivo PDF para download. Os artigos dessa edição estão disponíveis somente através do formato HTML.

O objeto TNMFTP

Compartilhe arquivos na Internet via FTP

 

O protocolo FTP (File Transfer Protocol) é um dos mais utilizados na Web, capacitando diferentes máquinas, com diferentes sistemas, a trocarem arquivos entre si. Sendo um dos primeiros protocolos implementados na Internet, o FTP deu origem a termos como download e upload. 

         Os servidores FTP podem ser públicos ou com acesso restrito. Na primeira situação, todos podem se conectar  e executar downloads ou uploads. Na outra hipótese, os usuários precisam estar cadastrados, ou seja, possuir um nome de conexão e uma senha. O servidor pode restringir o acesso a arquivos ou pastas, delegando poderes de leitura ou escrita para cada um. O componente TnmFTP é responsável pela criação de um aplicativo cliente FTP.

 

Nota: O exemplo a seguir cuidará da construção de um aplicativo cliente FTP - mas isto não significa que a funcionalidade deste componente se resume a este tipo  de software - várias situações podem ser solucionadas através deste protocolo. Veja alguns exemplos:

 

· Troca de arquivos de dados entre  aplicativos remotamente separados;

 

· Centralização de arquivos entre vários aplicativos;

 

· Recuperação de arquivos armazenados em outras plataformas, como linux, unix, e outras.

 

Vejamos como construir um aplicativo completo de FTP:

 

1) Efetuando a conexão com o servidor FTP:

 

         São necessárias três informações para efetuar a conexão: o endereço ftp, o nome do usuário e a senha. Insira três objetos Edit, três objeto Tlabel, um objeto tbutton e um objeto TstatusBar (palheta Win95/Win32). Configure suas propriedades de acordo com a tabela abaixo:

 

Tlabel

Caption                  Servidor

Tedit          

Name                    EditServer

 

Tlabel

Caption                  Username

 

Tedit

Name                    EditUsername

 

Tlabel

Caption                  Password

 

Tedit

Name                    EditPassword

 

Tbutton

Caption                  Conectar

 

TNmFTP

Name                    NmFtp1

 

TstatusBar

Name                    Status

 

* Crie um panel, utilizando a propriedade Panels

 

Selecione o objeto Tbutton e em seu evento OnClick digite:

 

procedure TForm1.Button1Click(Sender: TObject);

begin

 

if NMFTP1.Connected then  begin

      button1.Caption:='Conectar';

      NmFtp1.Disconnect;

End

Else begin

      NMFTP1.Host := EditServer.Text;

      NMFTP1.UserID := Editusername.Text;

      NMFTP1.Password := EditPassWord.Text;

      Status.Panels[0].Text:='Conectando...';

      nmFtp1.Timeout:=5000; //indica o tempo de espera, em milisegundos

      button1.enabled:=False;

      try

        NMFTP1.Connect;

        except

          button1.enabled:=true;

          Status.Panels[0].Text:='Erro na conexão';

      end;

End;

 

end;

 

Selecione o evento OnConnect do objeto TNMFTP, e insira o código abaixo:

 

procedure TForm1.NMFTP1Connect(Sender: TObject);

begin

  Status.Panels[0].text:='Conectado';

  Button1.Enabled:=True;

  Button1.Caption:='Desconectar';

end;

 

O evento OnConnect é gerado quando a conexão é estabelecida com sucesso. Se a conexão falhar, o evento OnConnectionFailed será executado:

 

procedure TForm1.NMFTP1ConnectionFailed(Sender: TObject);

begin

   Status.Panels[0].text:='Conexão falhou.';

  Button1.Enabled:=True;

end;

 

2) Recuperando uma lista de arquivos e pastas contidos no diretório FTP:

 

         Agora, o aplicativo deverá exibir a árvore de diretórios e arquivos da pasta FTP. Para incrementar o visual, iremos utilizar o objeto StringGrid encontrado na palheta Additional. Nosso form ficará parecido com a figura a seguir:

 

 

Configure o objeto StringGrid1 de acordo com a tabela abaixo:

 

TstringGrid

 

Name                              StringGrid1

Options.goColSizing            TRUE

Options.goRowSelect          TRUE

Options.goVertLine             FALSE

Options.goHorzLine            FALSE

Options.goRangeSelect       FALSE

FixedCols                        0

DefaultRowHeight              15

GridLineWidth                    0

ColCount                          4

RowCount                        2

 

No evento OnShow do formulário, iremos preencher o cabeçalho da grid e definir o tamanho das colunas:

 

procedure TForm1.FormShow(Sender: TObject);

begin

  StringGrid1.ColWidths[0]:=150;

  StringGrid1.ColWidths[1]:=35;

  StringGrid1.ColWidths[2]:=80;

  StringGrid1.ColWidths[3]:=50;

  StringGRid1.Cells[0,0]:='Arquivo';

  StringGRid1.Cells[1,0]:='Tam.';

  StringGRid1.Cells[2,0]:='Data';

  StringGRid1.Cells[3,0]:='Atributos'; 

end;

 

         Após efetuada a conexão, o aplicativo deverá ler o diretório do servidor FTP.  Este procedimento é efetuado através do método List. Este método lê a árvore de arquivos do servidor e  armazena na propriedade FtpDirectoryList.

 

Evento OnConnect:

 

procedure TForm1.NMFTP1Connect(Sender: TObject);

begin

  Status.Panels[0].text:='Conectado';

  Button1.Enabled:=True;

  Button1.Caption:='Desconectar';

  Screen.cursor:=crHourGlass;

  NmFtp1.List;

end;

 

Para que as informações sejam inseridas na propriedade FtpDirectoryList, a  propriedade ParseList do objeto TNMFTP1, deverá ser auterada para TRUE.

 

O StringGrid será preenchido no evento OnSuccess:

 

procedure TForm1.NMFTP1Success(Trans_Type: TCmdType);

var

 i:Integer;

begin

  case Trans_Type of

    cmdList:      begin

        StringGrid1.RowCount := NMFTP1.FTPDirectoryList.name.Count+2;

        StringGrid1.Cells[0,1]:='..';

        StringGrid1.Cells[3,1]:='d';

 

        for I := 0 to (NMFTP1.FTPDirectoryList.name.Count - 1) do  begin

   StringGrid1.Cells[0, I+2] := NMFTP1.FTPDirectoryList.name[I];

   StringGrid1.Cells[1, I+2] := NMFTP1.FTPDirectoryList.Size[I];

   StringGrid1.Cells[2, I+2] := NMFTP1.FTPDirectoryList.ModifDate[I];

   StringGrid1.Cells[3, I+2] := NMFTP1.FTPDirectoryList.Attribute[I];

         end;

        screen.cursor:=CrDefault;

      End;     

  end; 

end;

 

         O evento OnSuccess é chamado sempre que algum comando FTP é completado com sucesso. O parâmetro Trans_Type indica qual a operação que chamou o evento. No nosso caso, devemos nos preocupar com a execução do comando list, para  preencher o objeto StringGrid com as informações.

         Repare que  um loop FOR é executado, lendo todas as ocorrências do vetor FtpDirectorylist e preenchendo as informações no objeto Grid:

 

for I := 0 to (NMFTP1.FTPDirectoryList.name.Count - 1) do  begin

   StringGrid1.Cells[0, I+2] := NMFTP1.FTPDirectoryList.name[I];

   StringGrid1.Cells[1, I+2] := NMFTP1.FTPDirectoryList.Size[I];

   StringGrid1.Cells[2, I+2] := NMFTP1.FTPDirectoryList.ModifDate[I];

   StringGrid1.Cells[3, I+2] := NMFTP1.FTPDirectoryList.Attribute[I];

    end;

 

 

Caso algum erro aconteça, este será tratado no evento OnFailure:

 

procedure TForm1.NMFTP1Failure(var Handled: Boolean; Trans_Type: TCmdType);

begin

  Screen.Cursor:=CrDefault;

 

  Case Trans_Type of

    cmdList:

        Status.Panels[0].Text:='Erro durante a leitura do diretório';

 

  end;

end;

 

 

3) Modificando o diretório Corrente

 

É necessário que nosso aplicativo possa alterar o diretório atual, permitindo a navegação na árvore de diretórios. O método que permite a mudança de diretórios  é o ChangeDir. Sua sintaxe segue abaixo:

 

ChangeDir(novo_diretório: String);

 

         Neste momento, iremos criar uma interface simples, porém prática: a mudança será feita quando o usuário clicar duas vezes sobre o nome do diretório. Vamos ao evento OnDblClick do objeto StringGrid1:

 

procedure TForm1.StringGrid1DblClick(Sender: TObject);

begin

if nmFtp1.connected then

  if Copy(StringGRid1.Cells[3,StringGRid1.Row],1,1)='d' then  begin

     screen.cursor:=crHourGlass;

     NMFTP1.ChangeDir(StringGRid1.Cells[0,StringGRid1.Row]);

 End;

end;

 

         Os atributos do arquivo selecionado permanecem na coluna 4 do StringGrid. O primeiro passo é descobrir se o objeto selecionado é um diretório. Se for um diretório, a primeira letra do atributo deverá ser 'd'. A comparação é feita na linha:

 

if Copy(StringGRid1.Cells[3,StringGRid1.Row],1,1)='d' then begin

 

O diretório passado como parâmetro para o método ChangeDir será o nome da pasta clicada:

 

NMFTP1.ChangeDir(StringGRid1.Cells[0,StringGRid1.Row]);

 

O último passo é redesenhar a grade para que esta acompanhe a exibição do novo diretório selecionado. Vamos ao evento OnSuccess, do objeto NmFtp:

 

procedure TForm1.NMFTP1Success(Trans_Type: TCmdType);

var

 i:Integer;

begin

  case Trans_Type of

    cmdList:

      begin

        StringGrid1.RowCount := NMFTP1.FTPDirectoryList.name.Count+2;

        StringGrid1.Cells[0,1]:='..';

        StringGrid1.Cells[3,1]:='d';

        for I := 0 to (NMFTP1.FTPDirectoryList.name.Count - 1) do  begin

        StringGrid1.Cells[0, I+2] := NMFTP1.FTPDirectoryList.name[I];

        StringGrid1.Cells[1, I+2] := NMFTP1.FTPDirectoryList.Size[I];

        StringGrid1.Cells[2, I+2] := NMFTP1.FTPDirectoryList.ModifDate[I];

         StringGrid1.Cells[3, I+2] := NMFTP1.FTPDirectoryList.Attribute[I];

            end;

          screen.cursor:=crDefault;

      End; 

 

   cmdChangeDir: begin

          Status.Panels[0].Text:='Diretório alterado com sucesso.';

        mFtp1.List;

    End;

 

End;

end;

 

         Caso a operação ChangeDir tenha sido efetuada com sucesso, o método list é novamente executado, causando um redesenho no objeto StringGRid.

 

Nota: A primeira linha da grade, contendo o símbolo de dois pontos (..), já estará funcional. Isto porque o símbolo dois pontos é um comando universal para retorno de diretório.

 

         Para tratar algum  possível erro, modifique o evento OnFailure, de acordo com a listagem abaixo:

 

procedure TForm1.NMFTP1Failure(var Handled: Boolean; Trans_Type: TCmdType);

begin

  Screen.Cursor := crDefault;

 

  Case Trans_Type of

    cmdList:

      Status.Panels[0].Text:='Erro durante a leitura do diretório';

 

    cmdChangeDir:

       Status.Panels[0].Text:='Erro durante a mudança de diretório';

 

  end;

end;

 

4) Efetuando o Download

 

Insira um objeto Tbutton, um objeto SaveDialog e um objeto RadioGroup. Configure suas propriedades como segue abaixo:

 

Tbutton

Caption         Download

 

RadioGRoup

Items           ASCII BINÁRIO

ItemIndex     0

 

Tsavedialog

Name           SaveDialog1

Filter            *.*|*.*

 

No evento OnClick do botão Download, digite a rotina abaixo:

 

var

    LocalFile: String;

 begin

if nmFtp1.Connected then

  if Copy(StringGrid1.Cells[4,StringGRid1.Row],1,1)<>'d' then begin

      SaveDialog1.Filename:=StringGrid1.Cells[0,StringGRid1.Row];

 

      if saveDialog1.Execute then begin

        LocalFile:=SaveDialog1.Filename;

 

        case RadioGroup1.ItemIndex of

              0: NMFTP1.Mode(MODE_ASCII);

              1: NMFTP1.Mode(MODE_BYTE);

        end;

 

        screen.cursor:=crhourGlass;

        NMFTP1.Download(StringGrid1.Cells[0,StringGrid1.Row], Localfile);

        screen.cursor:=crDefault;

 

        Status.Panels[0].Text:='Download realizado com sucesso';

     end;

  end;

        

         Primeiramente, é verificado se o item selecionado é um arquivo. Isto será verdadeiro quando a primeira letra do atributo for diferente de 'd'.

         O objeto OpenDialog é executado, e o nome do arquivo de destino é salvo na variável LocalFile. Em seguida, é definido o modo de download do arquivo - se em formato texto ou binário. O usuário poderá fazer a seleção através do objeto TradioGroup:

 

case RadioGroup1.ItemIndex of

              0: NMFTP1.Mode(MODE_ASCII);

              1: NMFTP1.Mode(MODE_BYTE);

            end;

 

         O método Mode altera o modo atual de captura do arquivo. E por último o método download é executado. Veja sua sintaxe:

 

DownLoad(Arquivo_de_origem, arquivo_de_destino);

 

O nome do arquivo de origem é o próprio arquivo selecionado na grade. E  o arquivo de destino (local) é o arquivo selecionado no objeto OpenDialog:

 

NMFTP1.Download(StringGrid1.Cells[0,StringGrid1.Row], LocalFile);

 

NOTA: O método de transferência de arquivos indica como as quebras de linha serão representadas. O modo binário indica que não há quebra de linha, e o arquivo será transferido em sua forma original. Já o modo texto leva em consideração os caracteres de CR/LF, interpretando-os da forma necessária.

 

5) Efetuando o UpLoad

 

Inclua um objeto OpenDialog, um objeto botão, e configure sua propriedade Caption para Upload.

 

Em seu evento click, digite:

 

procedure TForm1.Button4Click(Sender: TObject);

var

  Arquivo:sTring;

  i:Integer;

begin

 

if nmFtp1.Connected then

     if OpenDialog1.Execute then begin

          Arquivo:=SingleFileName(OpenDialog1.Filename);

            case RadioGroup1.ItemIndex of

              0: NMFTP1.Mode(MODE_ASCII);

              1: NMFTP1.Mode(MODE_BYTE);

            end;

 

            screen.Cursor := CrHourGlass;

            NMFTP1.Upload(OpenDialog1.filename, Arquivo);

            Status.Panels[0].Text:='Arquivo transferido com sucesso';     End;

     end;

end;

 

         Repare que o nome do arquivo de destino é extraído do arquivo selecionado no objeto OpenDialog. A propriedade filename deste objeto retorna o nome do arquivo no formato longo, como por exemplo:

 

C:\windows\regedit.exe

 

E, na verdade, precisamos somente do nome puro do arquivo:

 

Regedit.exe

 

A função SingleFileName retorna o nome do arquivo da forma desejada. O código desta função está listado abaixo:

 

function SingleFilename(s:String):String;

var

 cont,

 l:Integer;

Begin

  result:=s;

  l:=-1;

  cont:=Length(s);

  while cont>0 do begin

    if Copy(s,cont,1)='\' then begin

      l:=cont;

      cont:=-1;

    end;

    cont:=cont-1;

  End;

 

  if l>0 then result:=Copy(s,l+1,length(s)-l);

End;

 

         O método Upload é o responsável pela transferência do arquivo ao servidor. Sua sintaxe é:

 

Upload(Arquivo_de_origem, Arquivo_de_Destino)

O objeto TNmFtp, disponibiliza ainda outros recursos, como a criação de diretórios, remoção de arquivos, status de download/upload. O aplicativo de FTP,  que utiliza todos estes recursos,  foi construído sobre a base desta matéria e está disponível, com fontes, no endereço www.clubedelphi.com.br/exemplos/ftp.zip

 

Artigos relacionados