Upload
others
View
8
Download
0
Embed Size (px)
Citation preview
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
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.
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;
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;
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;
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
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
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
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]
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>
<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.
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
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.
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]
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.
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.
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.
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;
}
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);
}
}
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]