Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o...

21

Transcript of Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o...

Page 1: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,
Page 2: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,

Caro leitor,

A nossa equipe deseja a você que este início de ano seja repleto de alegria, saúde e paz! Que continuemos

caminhando juntos rumo ao sucesso!

A revista The Club Megazine está como sempre recheada de artigos de diversos assuntos. Nosso colunista Luciano

Pimenta nos traz o artigo “Delphi e Android”, abordando dicas e truques para desenvolver aplicativos para o S.O. Android

utilizando a IDE do Delphi.

Já nosso colaborador Hamden Vogel redigiu a segunda parte do artigo “THVDataSetStream – DataSet baseado

em TStream”. Nesta parte ele demonstra o funcionamento do componente na prática, com algumas funcionalidades,

sendo útil em vários tipos de aplicações.

O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre

o escopo do AngularJS”, criando exemplos práticos utilizando este Framework do Google.

Para finalizar, Thiago C. Montebugnoli desenvolveu um artigo utilizando a Linguagem C#, junto com Windows

Forms trabalhando com FTP de arquivos. Ele Procurou abranger algumas dicas partindo de blocos de códigos de fácil

implementação.

Desejo uma ótima leitura e que este ano de 2016 seja ainda melhor que o ano passado

Um abraço!

Marcos César Silva

Diretor Técnico

Editorial

Page 3: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,

THVDataSetStream – DataSet baseado

em TStream – parte 2

Nesta parte, vamos dar sequência ao funcionamento do componente THVDataSetStream, ou

seja, mostrar ele na prática. Vamos abordar suas funcionalidades e ver como ele pode ser útil em vários

tipos de aplicações possíveis em que um pequeno/médio banco de dados possa ser usado.

Este componente não visa substituir nem concorrer às classes alternativas baseadas em TDataSet

encontradas no mercado – por enquanto, é uma versão “soft” – sem muitas peculiaridades a mais – não

há por exemplo suporte a SQL, filtros avançados, carregamento em memória, etc – esta implementação

é uma alternativa e um aprendizado de uma release inicial que possa ser evoluída com o tempo – é um

componente baseado em TStream, que possa ser utilizado neste mundo desta classe pai com várias

oportunidades, como aperfeiçoar seu método “copyfrom”, migrando do nosso componente para um

TMemoryStream, por exemplo. Existem muitos cenários possíveis e imaginários a serem percorridos

neste sentido. E por enquanto vamos nos ater ao básico: o funcionamento normal esperado de qualquer

TDataSet.

É importante notar que este descendente de TDataSet também é descendente de TStream, e

por isso pode suportar várias funcionalidades ou até mesmo estender outras novas – e como o nosso

arquivo de banco de dados é baseado em arquivos (objeto de TFileStream) – ele pode suportar a

quantidade de dados limitada à memória disponível – contanto que não seja um arquivo

demasiadamente grande a nossa solução poderá funcionar estável sem problemas de travar o DBGrid

sem problemas.

É Outra coisa interessante é que o componente só precisa do layout pra funcionar. Este layout

como visto anteriormente é onde informará as colunas que ele vai criar e ler os dados. Sem isso o

componente não seria capaz de abrir o arquivo. Basta informar na propriedade “TableName” o caminho

completo da tabela, mas sem extensão nenhuma – nosso banco de dados não terá nunca extensão – e

assim o componente irá criar a tabela se ela não existir. O nome do layout é o mesmo nome da tabela

(TABELA CLIENTES => nome do layout => CLIENTES.header => nome da tabela => CLIENTES (só

“CLIENTES”, sem extensão!).

Portanto, com o layout já criado pelo nosso programa wizard explicado no artigo anterior, basta

especificar ele no caminho completo desta propriedade “TableName” (lembre-se de tirar a extensão

“header” da string do valor de “TableName” – a tabela não tem extensão). E assim a tabela será criada.

O bom disso é que não precisamos mais nos preocupar (como a maioria dos descendentes de

TDataSet´s que eu já vi) se a tabela existe ou não antes de ser criada, emitindo erros de “not found”, etc.

Isso será feito de forma transparente para o usuário. Uma última observação é que a tabela deverá ser

fechada quando a execução do programa for iniciada, senão o Delphi emitirá um erro de “arquivo

sendo usado por outro processo” – neste caso basta setar a propriedade Active para False e executar

novamente o programa. Mas a tabela poderá ser aberta sem nenhum problema no modo Design pelo

Object Inspector sem problemas também.

Page 4: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,

Figura 01 – Tela de exemplo do nosso programa em tempo de execução.

Nesta tela podemos ver que o componente abriu com sucesso a tabela de “clientes” cujo layout

foi especificado anteriormente, no último artigo onde abordamos o programa para gerar layouts

(wizard) – o componente portanto abre e processa ele, dando sequência para a criação destes campos

(em caso de sucesso) dentro do método sobreescrito de TDataSet chamado InternalInitFieldDefs. Segue

abaixo o fonte responsável por isso:

procedure THVDataSetStream.InternalInitFieldDefs;

var

fHeaderFileName: string;

parser: THVParser;

Begin

fHeaderFileName := ChangeFileExt(FTableName, '.header');

if not FileExists(fHeaderFileName) then

raise EHVDataSetError.Create('The header file must be created

before!'); Settings.LoadFromFile(fHeaderFileName);

parser := THVParser.Create;

Page 5: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,

Figura 02 –Aplicação de Filtro, ativado através do checkbox correspondente (“filtered =true”).

No evento OnFilterRecord de THVDataSetStream faremos o recurso de filtro, que é a

localização (no caso exata) para os nossos registros – não há nesta versão suporte para localizações

parciais, nem outro suporte a filtros além deste.

function THVCustomDataSet.HVFilterRecord(Buffer: PChar): Boolean;

var

SaveState: TDatasetState;

begin

Result:=True;

if not Assigned(OnFilterRecord) then Exit;

SaveState:=SetTempState(dsFilter);

FFilterBuffer:=Buffer;

OnFilterRecord(self,result);

RestoreState(SaveState);

end;

procedure TfrmMain.HVDataSetStream1FilterRecord(DataSet: TDataSet;

var Accept: Boolean);

begin

//Edit1 => fieldName

//Edit2 => value to search from fieldName of Edit1

Accept:=(DataSet[Edit1.Text] = Edit2.Text);

end;

Page 6: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,

Figura 03 – Exemplo de uma inclusão de um registro novo.

No método sobreescrito InternalAddRecord sempre incluímos para o fim do arquivo (TStream)

nosso novo registro. Isso é feito chamando o método sobreescrito InternalLast (ir para a posição

especial após o último registro – o “crack”) e após essa chamada apontamos para a constante

soFromEnd de TStream para a sua posição final, pois movendo ele para o fim é que inserimos seus

novos dados – sempre a partir do fim.

// II: Go to a special position after the last record

procedure THVCustomDataSet.InternalLast;

begin

EofCrack := InternalRecordCount;

FCurrentRecord := EofCrack;

end; // III: Add the current data to the file

procedure THVDataSetStream.InternalAddRecord(

Buffer: Pointer; Append: Boolean);

begin

// always append at the end

InternalLast;

FStream.Seek (0, soFromEnd);

FStream.WriteBuffer (ActiveBuffer^, FRecordSize);

Inc (FRecordCount);

end;

Page 7: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,

Figura 04 e 05 – Exemplo de remoção de um determinado registro.

Para remover um registro, aparentemente para sua visualização é tranquila, pois

tradicionalmente o “refresh” da grid é executado e a coluna é removida. Mas foi o método que trouxa

um pouco mais de complexidade, pois o nosso objeto de TStream tem que tirar o registro “como

abastecer um avião em pleno voo” – ou seja, recalculando seus itens – e isso terá três situações possíveis

a serem avaliadas:

1. O item a ser excluído é o primeiro registro. Então o THVDataSetStream obterá o restante

dos itens (se houver), salvar em um objeto de TStream auxiliar e carregar ele para o

nosso THVDataSetStream de volta.

2. O item a ser excluído é um registro entre o início e o fim. Neste caso o

THVDataSetStream obterá todos os registros antes deste registro a ser eliminado em

um objeto auxiliar de TStream, vai carregar ele de volta, e após isso vai obter todos os

Page 8: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,

registros depois deste registro a ser eliminado, vai salvar novamente neste objeto

auxiliar de TStream e vai carregar novamente no THVDataSetStream de volta. Fazendo

isso todos os registros serão carregados menos o registro marcado para ser eliminado

– portanto ele será eliminado por ser “esquecido” através dos carregamentos auxiliares

deste TStream. É muito eficiente visto que fará o papel de remoção sem problemas, e

de forma tranquila para o componente.

3. O registro a ser excluído é o último registro. Neste caso o THVDataSetStream carregará

todos os registros menos o último, deletando diretamente o último registro (variável

referenciada internamente FStream).

procedure THVDataSetStream.InternalDelete;

var

FAuxStream: TMemoryStream;

begin

FAuxStream := TMemoryStream.Create;

FAuxStream.Clear;

FAuxStream.Position := 0;

try

if (FCurrentRecord = 0) then //first record

begin

FStream.Position:=GetRecStreamPos(FCurrentRecord+1);

FAuxStream.Clear;

FAuxStream.CopyFrom(FStream,(GetRecStreamPos(FRecordCount))-

GetRecStreamPos(FCurrentRecord+1));

FStream.CopyFrom(FAuxStream,0);

FAuxStream.Clear;

Self.DeleteFromStream(FStream,

GetRecStreamPos(FCurrentRecord), GetRecStreamPos(FRecordCount));

dec(FRecordCount);

end

else if (FCurrentRecord > 0) and (FCurrentRecord < FRecordCount-

1) then

begin

FStream.Position:=GetRecStreamPos(0); //middle record

FAuxStream.Clear;

FAuxStream.CopyFrom(FStream, GetRecStreamPos(FCurrentRecord)-

GetRecStreamPos(0));

FStream.Position:=GetRecStreamPos(FCurrentRecord+1);

FAuxStream.CopyFrom(FStream,(GetRecStreamPos(FRecordCount))-

GetRecStreamPos(FCurrentRecord+1));

Self.DeleteFromStream(FStream, GetRecStreamPos(0),

GetRecStreamPos(FRecordCount));

FStream.Position := 0;

FStream.Seek (0, soFromBeginning);

FStream.CopyFrom(FAuxStream,0);

FAuxStream.Clear;

dec(FRecordCount);

end

Page 9: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,

else if (FCurrentRecord = FRecordCount-1) then //last record

begin

FStream.Position:=GetRecStreamPos(FCurrentRecord);

Self.DeleteFromStream(FStream,

GetRecStreamPos(FCurrentRecord), GetRecStreamPos(FRecordCount-1));

dec(FRecordCount);

end;

finally

FreeAndNil(FAuxStream);

end;

end;

procedure THVDataSetStream.DeleteFromStream(Stream: TStream; Start,

Length: Int64);

var

Buffer: Pointer;

BufferSize: Integer;

BytesToRead: Int64;

BytesRemaining: Int64;

SourcePos, DestPos: Int64;

begin

SourcePos := Start+Length;

DestPos := Start;

BytesRemaining := Stream.Size-SourcePos;

BufferSize := Min(BytesRemaining, 1024*1024*16);//no bigger than

16MB

GetMem(Buffer, BufferSize);

try

while BytesRemaining>0 do begin

BytesToRead := Min(BufferSize, BytesRemaining);

Stream.Position := SourcePos;

Stream.ReadBuffer(Buffer^, BytesToRead);

Stream.Position := DestPos;

Stream.WriteBuffer(Buffer^, BytesToRead);

inc(SourcePos, BytesToRead);

inc(DestPos, BytesToRead);

dec(BytesRemaining, BytesToRead);

end;

Stream.Size := DestPos;

finally

FreeMem(Buffer);

end;

end;

Conclusão

Vimos as principais abordagens esperadas de um dataset normal, como edição, inserção,

exclusão e localização. Além disso, vimos uma customização própria e original do nosso

THVDataSetStream para criar as tabelas. Podemos seguramente utilizar este nosso novo dataset em

aplicações como registro de log´s, versionamento, sistema de clientes, baselines, contas, enfim, as

possibilidades são inúmeras em que um banco de dados possa ser empregado. Não estou enfatizando

Page 10: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,

seu uso no lugar de um banco de dados profissional com suporte a SQL, transações, etc – o foco é

utilizar ele de forma simples em uma aplicação que não necessite de muitos recursos da máquina – um

banco local como alternativa ao XML ou Paradox, por exemplo. Podemos utilizar este componente em uma versão demo para um cliente, acessado inclusive

por uma mídia portátil (CD, Pen-Drive, etc) sem problema algum, acessando a tabela normalmente.

Podemos também utilizar em cinco tipos de dados, que são os ftString, ftInteger, ftBoolean, ftFloat,

ftDate. Somente eles são suportados pelo nosso THVDataSetStream.

Bons estudos com o componente! Aproveite em várias aplicações e divirtam-se com o mesmo

prazer que eu tive em desenvolver ele!

Sobre o Autor

Hamden Vogel Consultor TheClub

E-mail: [email protected]

Page 11: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,

Introdução ao Escopo do AngularJS

Fala pessoal, tudo bem? Hoje nós vamos falar sobre uma das partes mais importantes do Angular JS, o escopo.

Introdução

Os escopos ou scopes, como iremos chamar daqui para frente, são uma parte fundamental de qualquer

aplicação Angular. É muito importante saber como eles funcionam pois eles estão todas as partes do framework.

É a partir dos escopos que nós iremos definir as regras de negócios de nossa aplicação, os métodos em nossos

controles e as propriedades em nossas views, portanto é possível dizer que o escopo é a cola que une o controller

com a view.

Antes de sua aplicação renderizar a view e a aplicação criar o DOM para o usuário, o template da view é ligado

ao escopo para notificar o Angular para popular o DOM com os valores.

Alguns escritores costumam chamar o escopo de fonte da vida, pois é através dele que acontece o data

binding que explicamos no artigo anterior, ele é o responsável por alterar os valores imediatamente na view e nos

modelos quando há alguma mudança em qualquer um dos lados.

Características

O scope possui algumas características muito importantes, algumas são mais avançadas e não serão tratadas

neste artigo, mas importante que você saiba o porque de ele ser tão importante:

1. O scope fornece a API $watch para observar as alterações no modelo.

2. O scope fornece também uma API $apply para propagar as mudanças.

Você pode criar escopos filhos, assim você poderá compartilhar as informações comuns a vários escopos no

escopo pai enquanto cada informação específica ao escopo filho fica armazenado no escopo filho.

Usando o scope como Data-Model

Durante a fase de ligação do template, as diretivas implementam expressões $watch no escopo. As expressões

$watch permitem que as diretivas sejam notificadas ao modificar um valor de uma propriedade, permitindo assim, que

a diretiva atualize o valor no DOM assim que ele for alterado.

Tanto o controller quanto as diretivas possuem referências ao escopo, mas não um para o outro diretamente.

Isso faz com que o controller esteja isolado das diretivas e consequentemente do DOM. Isso é importante, pois

possibilita um melhor controle nos testes de nossa aplicação, facilitando a criação de cenários de testes.

Para entendermos melhor o que foi dito vamos a um exemplo dos exemplos mais clássicos, o Hello World:

Arquivo index.html

<!doctype html>

<html>

<head>

<meta charset="UTF-8">

<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.0-

rc.0/angular.min.js"></script>

<script src="script.js"></script>

</head>

Page 12: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,

<body ng-app=“exemploEscopo”>

<div ng-controller=“MeuControlador”>

<span>Seu nome:</span>

<input type="text" ng-model=“usuario”>

<button ng-click='sayHello()'>saudar</button>

<hr>

{{saudacao}}

</div>

</body>

</html> <!-- fim do arquivo index.html -->

Arquivo script.js

(function(angular) {

'use strict';

angular.module('exemploEscopo', []).controller('MeuControlador', ['$scope',

function($scope) {

$scope.usuario = 'World';

$scope.sayHello = function() {

$scope.saudacao = 'Hello ' + $scope.usuario + '!';

};

}]);

})(window.angular); // fim do arquivo script.js

Antes de falarmos sobre o escopo, podemos notar duas modificações em relação ao código dos artigos

anteriores. A primeira que não utilizamos mais o Bower para instalar nossas dependências, pois como se trata de um

projeto pequeno não há a necessidade de baixar todo o pacote que acompanha o Bower.

A segunda é que utilizamos o Java Script do AngularJS direto do CDN do Google, isso é sempre considerado

uma boa prática pois muito provavelmente o arquivo já estará em cache no navegador do usuário.

Voltando ao exemplo, vemos que o controller MeuController atribui o valor World para a variável usuario. O

escopo notifica o input que renderiza a página com o valor pré-estipulado, como pode ser observado na Figura 1 que

mostra como o controller consegue escrever informações no escopo.

Da mesma forma o controller consegue acessar o escopo quando atribui um comportamento ao método

sayHello, que é invocado ao clicar no botão saudar. O método sayHello consegue ler a variável usuario e criar a

propriedade saudação.

Figura 1 – Exemplo do input com valor pré-estipulado.

Page 13: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,

Hierarquia

Cada aplicação Angular possui somente um escopo raiz, conhecido como root scope, mas pode ter vários

“escopos filhos”. Para demonstrarmos melhor como funcionam a hierarquia nos escopos vamos usar o seguinte exemplo:

Arquivo index.html

<!doctype html>

<html lang="pt_BR">

<head>

<meta charset="UTF-8">

<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-

rc.0/angular.min.js"></script>

<script src="script.js"></script>

</head>

<body ng-app="exemploEscopo">

<div>

<div ng-controller="OlaController">

Olá {{nome}}!

</div>

<div ng-controller="ListagemController">

<ol>

<li ng-repeat="nome in nomes">{{nome}} de {{filme}}</li>

</ol>

</div>

</div>

</body>

</html> <!-- fim do arquivo index.html -->

Arquivo script.js

(function(angular) {

'use strict';

angular.module('exemploEscopo', [])

.controller('OlaController', ['$scope', '$rootScope', function($scope,

$rootScope) {

$scope.nome = 'World';

$rootScope.filme = 'Star Wars';

}])

.controller('ListagemController', ['$scope', function($scope) {

$scope.nomes = [

'Daisy Ridley',

'Harrison Ford',

'Mark Hamill',

'Adam Driver'

];

}]);

})(window.angular); // fim do arquivo script.js

Page 14: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,

Quando o Angular for calcular o valor da variável nome, ele primeiramente irá procurar no escopo associado

ao elemento. Se a variável não for encontrada ele irá procurar no “escopo pai” e assim por diante até achar o valor ou

o escopo raiz ser alcançado. Em Java Script esse comportamento é conhecido como prototypical inheritance, que pode

ser traduzido como herança prototípica, e podemos dizer que os escopos filhos herdam prototipicamente seus pais. Isso pode ser um pouco confuso para programadores de linguagens baseadas em classes (como Java ou C++),

porque o Java Script é dinâmico e não possui uma implementação de classes. Quando se trata de herança, Java Script

tem somente um construtor: objetos. Cada objeto possui um link interno para um outro objeto que chamamos de

prototype. Esse objeto prototype também tem um atributo prototype, e assim por diante até que null seja encontrado

como prototype (como em uma implementação de fila em C, por exemplo). Esse comportamento pode ser observado

na Figura 2.

Figura 2 – Exemplo da prototypical inheritance

Assim, como a Figura 2 nos mostra, o Olá {{nome}} é renderizado como Olá World, pois a variável nome no

escopo do controller OlaController é World e posteriormente no escopo ListagemController, ao iterar pela listagem

nomes a variável assume um valor diferente. A Figura 3 demostra a mudança de valores nos diferentes escopos.

Figura 3 – Mudança no valor da variável nome em diferentes escopos.

Uma outra novidade contida neste exemplo é a tag ng-repeat, ela é uma diretiva que instancia um template

para cada item de uma coleção. Cada template possui seu próprio escopo que é o item que está sendo iterado e uma

variável $index que determina a posição do elemento na coleção.

Page 15: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,

Conclusão

No artigo de hoje nós tratamos de um assunto um pouco mais complexo, mas essencial para continuarmos

nossos estudos com o AngularJS. Uma vez que o conceito do escopo esteja claro fica muito mais fácil o entendimento

dos próximos passos que são módulos mais complexos e diretivas personalizadas.

Recomendo que esse assunto seja bastante estudado e que você pratique muito, principalmente a hierarquia

entre os escopos. Bons estudos e até a próxima!

Sobre o Autor

Ricardo Barbosa Crivelli mais conhecido como Rico, é formado como Bacharel em Sistemas de Informação e

Licenciado em Computação pela Universidade Estadual do Norte do Paraná, atualmente é Técnico em TI no Instituto Federal de São Paulo – Câmpus Avaré. Tem como especialidade a linguagem PHP e o framework Symfony, apesar de adorar trabalhar com front-end e desenvolvimento mobile e possuir as certificações COBiT 4.1 Foundation e Delphi 2006 Developer.

E-mail: [email protected]

Page 16: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,

Linguagem C# - Ftp de Arquivos

Caro leitor, antes de iniciar o artigo, gostaria de desejar um ótimo início de ano 2016. Neste mês irei abordar

o uso de FTP na linguagem C# junto utilizando como plataforma de referrência os denominados Formulários Windows.

Para relembrá-lo, FTP (File Transfer Protocol) e traduzindo para o português, “Protocolo de Transferência de

Arquivos”, é uma forma bastante rápida e versátil de transferir arquivos, sendo uma das mais usadas na Internet.

(Fonte: Wikipedia)

Podemos destacar as duas principais classes quando trabalhamos com FTP na arquitetura .NET, a

“FtpWebRequest” (utilizaremos neste artigo) e a “FtpWebResponse”. A classe “FtpWebRequest” implementa um cliente

de protocolo de transferência de arquivo. Já a “FtpWebResponse” encapsula a resposta do servidor FTP a uma

solicitação. Ambas são de origem do Namespace “System.Net” e do Assembly “System.dll”. Segue abaixo

hierarquia de herança para entendermos melhor.

FtpWebRequest

FtpWebResponse

System.Object

System.MarshalByRefObject

System.Net.WebRequest

System.Net.FtpWebRequest

System.Object

System.MarshalByRefObject

System.Net.WebResponse

System.Net.FtpWebResponse

Para este artigo criaremos uma classe chamada “Ftp” contendo algumas propriedades e métodos necessários.

A partir desta classe criaremos uma interface para instanciá-la posteriormente. Nesta primeira parte codificaremos

apenas o método chamado “Upload”, o qual será responsável por encapsular e enviar dados a um servidor FTP.

Criando a Classe Ftp

Crie um projeto desde o início do tipo Windows Forms clicando em (File/New/Project.../Windows Forms

Application). Para adicionar uma classe dê um clique com o botão direito sobre a “Solution” escolhendo “Add/New

Item...” e definindo o nome como “Ftp”. Ver Imagem 01.

Page 17: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,

Figura 01: Criando a classe Ftp.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

Deveremos declarar alguns namespaces para trabalhar com métodos de classes

referentes ao FTP, Arquivos e Streams.

using System.IO;

using System.Net;

namespace WindowsFormsFTP

{

public class Ftp

{

Teremos alguns atributos privados, sendo o endereço do FTP, usuário, senha e uma variável “ftprequest” a qual

será feita a requisição do serviço FTP.

private string enderecoFtp = null;

private string usuario = null;

private string senha = null;

private FtpWebRequest ftpRequest = null;

No método construtor passaremos por parâmetro o endereço, usuário e senha.

Page 18: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,

public Ftp(string endFtp, string usu, string sen)

{

enderecoFtp = endFtp;

usuario = usu;

senha = sen;

}

O Método Upload será encarregado de efetuar toda a tarefa de subir o arquivo ao servidor por FTP. Passaremos

por parâmetro o caminho do arquivo remoto e local. Faremos um tratamento através do bloco “try/catch” retornando

um valor booleano, nos informando sucesso na operação. Primeiramente instanciamos a variável FTPRequest

informando o endereço completo do arquivo FTP e logo em seguida atribuímos algumas propriedades, como por

exemplo: “Method” para o tipo de operação Upload, “Proxy” se possui ou não proxy, “UseBinary” para dados binários e

“Credencials” para inserir usuário e senha. O uso da classe “FileInfo”, “FileStream” e “Stream” irá transportar o arquivo

para o servidor FTP.

public bool Upload(string remoteFile, string localFile)

{

try

{

ftpRequest = (FtpWebRequest)FtpWebRequest.Create(new

Uri(string.Format("{0}/{1}", enderecoFtp, remoteFile)));

ftpRequest.Method = WebRequestMethods.Ftp.UploadFile;

ftpRequest.Proxy = null;

ftpRequest.UseBinary = true;

ftpRequest.Credentials = new NetworkCredential(usuario, senha);

FileInfo arquivo = new FileInfo(string.Format("{0}", localFile));

byte[] fileContents = new byte[arquivo.Length];

using (FileStream fr = arquivo.OpenRead())

{

fr.Read(fileContents, 0, Convert.ToInt32(arquivo.Length));

}

using (Stream writer = ftpRequest.GetRequestStream())

{

writer.Write(fileContents, 0, fileContents.Length);

}

ftpRequest = null;

return true;

}

catch

{

return false;

}

}

}

}

Criando um exemplo prático

Nosso formulário deverá conter a seguinte estrutura: 4 pares de Labels e TextBox sendo (Endereço Ftp, Usuário,

Senha e Caminho do Arquivo local), um botão para localizar o arquivo a ser enviado e por último o botão “Upload”, o

qual fará o trabalho de subir o arquivo no servidor FTP. Ver Imagem 02.

Page 19: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,

Figura 02: Criando a interface gráfica para consumir a classe Ftp.

A função “consistencias” será responsável por obrigar o preenchimento de todos os campos do formulário.

private bool consistencias()

{

if (txtEndereco.Text.Length <= 0)

{

MessageBox.Show("O campo Endereço Ftp é de preenchimento obrigatório!",

"Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning);

return false;

}

if (txtUsuario.Text.Length <= 0)

{

MessageBox.Show("O campo Usuário é de preenchimento obrigatório!",

"Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning);

return false;

}

if (txtSenha.Text.Length <= 0)

{

MessageBox.Show("O campo Senha é de preenchimento obrigatório!",

"Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning);

return false;

}

if (txtArquivo.Text.Length <= 0)

{

MessageBox.Show("O campo Arquivo é de preenchimento obrigatório!",

"Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning);

return false;

}

return true;

}

Page 20: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,

No evento “Click” do botão procurar iremos implementar a classe “OpenFileDialog”, a qual irá escolher o arquivo

para ser enviado ao servidor. Será necessário definir algumas propriedades de controle como: “MultiSelect” para permitir

a multi-seleção de arquivos, “Title” da caixa de pesquisa, “InitialDirectory” para o diretório inicial, “Filter” para filtrar

arquivos, “CheckFileExists” e “CheckPathExists” para identificar se existe arquivo e diretório e “RestoreDirectory” para

restaurar diretórios. Por final atribuíremos ao “txtArquivo”.

private void btnProcurarArquivo_Click(object sender, EventArgs e)

{

OpenFileDialog filedialog = new OpenFileDialog();

filedialog.Multiselect = false;

filedialog.Title = "Selecionar Arquivos";

filedialog.InitialDirectory = @"C:\";

filedialog.Filter = "All files (*.*)|*.*";

filedialog.CheckFileExists = true;

filedialog.CheckPathExists = true;

filedialog.RestoreDirectory = true;

DialogResult dr = filedialog.ShowDialog();

if (dr == System.Windows.Forms.DialogResult.OK)

{

txtArquivo.Text = filedialog.FileName;

}

}

No evento “Click” do botão “Upload” iremos utilizar a função “consistências” para logo em seguida instanciar a

classe “Upload” inserindo todos os valores dos “TextBoxes” conforme listagem de código abaixo.

private void btnUpload_Click(object sender, EventArgs e)

{

if (consistencias() == true)

{

string nomeArquivo = System.IO.Path.GetFileName(txtArquivo.Text);

Ftp ftp = new Ftp(txtEndereco.Text, txtUsuario.Text, txtSenha.Text);

if (ftp.Upload("thiago/" + nomeArquivo, txtArquivo.Text))

MessageBox.Show(string.Format("Arquivo {0} enviado ao servidor com

sucesso!", nomeArquivo), "Informação", MessageBoxButtons.OK,

MessageBoxIcon.Information);

}

else

{

MessageBox.Show(string.Format("Ocorreu uma falha no envio do arquivo {0} ao

servidor!", nomeArquivo), "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);

}

}

Page 21: Diretor Técnico - The Club · 2018-11-26 · O colunista Ricardo Barbosa Crivelli continua com o tema sobre AngularJS, com o artigo “Uma introdução sobre o escopo do AngularJS”,

Podemos conferir o exemplo em Run-time na Figura 03.

Figura 03: Exemplo em Run-time.

Conclusões

Vimos neste artigo uma forma simples e prática de “Upload” de arquivos por FTP usando a plataforma .NET.

Criamos

uma classe para esta tarefa podendo ser reutilizada conforme a necessidade do programador. Para o mês que vem irei implementar o método para “Download” de arquivos.

Fica aí a dica, um abraço e até o mês que vem!

Referências

https://pt.wikipedia.org/wiki/File_Transfer_Protocol

https://msdn.microsoft.com/pt-

br/library/system.net.ftpwebresponse(v=vs.110).aspx

https://msdn.microsoft.com/pt-

br/library/system.net.ftpwebrequest(v=vs.110).aspx

Sobre o Autor

Thiago Cavalheiro Montebugnoli Adora aprender novas tecnologias. Formado pela Faculdade

de Tecnologia de Botucatu – SP (FATEC), já desenvolveu softwares utilizando a plataforma .NET, Delphi junto com Banco de Dados SQL Server e Firebird. Como experiências profissionais mais recentes, possui em seu currículo sua atuação no Centro de Processamento de Dados da Prefeitura Municipal de Itaí-SP e atualmente compõe a equipe da

Coordenadoria Tecnologia da Informação no IFSP – Instituto Federal do Estado de São Paulo em Avaré. Além disso, é colunista mensal da Revista The Club Megazine e é consultor Técnico do The Club. Possui as seguintes certificações:

MCP - Microsoft Certified Professional, MCTS - Microsoft Certified Technology Specialist, MCAD - Microsoft Certified Application Developer e MCSD - Microsoft Certified Solution Developer.

E-mail: [email protected]