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



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