32
dezembro 2011

The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

  • Upload
    others

  • View
    3

  • Download
    10

Embed Size (px)

Citation preview

Page 1: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 2011

Page 2: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 2011

Page 3: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 2011 03

Desafio The Club

- Dicas Delphi

Dicas

- Cruzada

30

Delphi Delphi

DelphiDelphi

Métodos RAVReport - de A a Z - parte 3

Comunicado:

Seguindo nossa tradição, o The Club estará em recesso do dia 19 de dezembro de 2011 a 30 de dezembro de 2011.

índiceIntrudução ao Android com SQLite

Editorial

10Chegamos a mais um final de ano.

Mais uma vez foi uma grande honra para to-dos nós do The Club estar com vocês as-sociados... 04

Criando uma aplicação Client-server no Delphi - Parte 2 05

Streams e compressão de arquivos com ZipMaster em Delphi 15

28

22

LegendaInicianteIntermediárioAvançado

Autor:Thiago Cavalheiro Montebugnoli

Autor: Antonio Spitaleri

Autor:Luciano Pimenta

Autor: Leonora Golin

Page 4: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 201104

Bem-vindo

Delphi é marca registrada da Borland International, as demais marcas citadas são registradas

pelos seus respectivos proprietários.

Antonio Spitaleri Neto - Editor [email protected]

Chegamos a mais um final de ano. Mais uma vez foi uma grande honra para todos nós do The Club estar com vocês associados auxiliando nas mais diversas dúvidas e tornando esse trabalho de desenvolver sistemas mais fácil.

Claro que não é porque estamos no final do ano que nossos artigos serão mais “light”. Preparamos para esse mês grandes matérias e dicas para essa última revista do ano.

Para começar, temos a continuação da matéria de nosso colaborador Luciano Pimenta: “Criando uma aplicação client – server no Delphi parte 2”, mostrando como aplicações client – server podem ser uma grande alternativa na programação Delphi.

Na sequência, temos outra continuação. Dessa vez, nosso colaborador Thiago Montebugnoli segue nos mostrando a plataforma Android, trazen-do como utilizar o banco de dados Sqlite com essa plataforma, no artigo “Introdução ao Android com Sqlite”.

No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações Delphi e podem agilizar diversas ações que eventualmente precisemos realizar na manipulação de arquivos.

Para fechar, temos a terceira parte do artigo de Leonora Golin sobre os métodos do Rave Report no artigo “Métodos Rave Report A a Z”.

Por esse mês é isso. Nós do The Club desejamos um feliz Natal e um grande e próspero Ano Novo a todos e esperamos que nossa parceria con-tinue por muito tempo.

Abraços a todos e até 2012!

Av. Profº Celso Ferreira da Silva, 190 Jd. Europa - Avaré - SP - CEP 18.707-150

Informações e Suporte: (14) 3732-1529

Internethttp://www.theclub.com.br

Cadastro: [email protected]: [email protected] Informações: [email protected] Cadastro: theclub_cadastro

Skype Suporte: theclub_linha1 theclub_linha2 theclub_linha3

www.twitter.com/theclubbr

Copyright The Club Megazine 2009

Diretor TécnicoMarcos César Silva

Diagramação e ArteVitor M. Rodrigues

RevisãoEliziane Valentim

ColunistasAntonio Spitaleri Neto

Bruno AlcarásEduardo Massud

Leonora GolinLuciano Pimenta

Thiago Cavalheiro Montebugnoli

Impressão e acabamento:GRIL - Gráfica e Editora

Taquarituba-SP - Tel. (14) 3762-1345

ReproduçãoA utilização, reprodução, apropriação, armazenamento em banco de dados, sob qualquer forma ou meio, de textos, fotos e outras criações intelectuais em cada publicação da revista “The Club Megazine” são terminantemente proibidos sem autorização escrita dos titulares dos direitos autorais.

Page 5: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 2011 05

Delphi

Começamos no artigo anterior a criação de uma aplicação cliente-server no Delphi, onde mostrei dicas e maneiras corretas para usarmos esse tipo de arquitetura em nossos projetos. A maneira correta (não sou o dono da verdade, apenas quero mostrar uma maneira eficiente de desenvolvimento), se refere a utilização de OO nas telas de cadas-tro, onde usamos os conceitos de herança e polimorfismo.

Nesse artigo, vamos aprofundar alguns conceitos de OO, onde vamos criar uma classe, que será a responsável por manipular os dados com o banco. Não vou criar aqui um framework de persistência, longe disso. Quero apenas mostrar outra forma de utili-zarmos classes em aplicações cliente-server no Delphi, que tem por objetivo manipular dados no banco.

Criando a classe

Criando uma aplicação client-server no Delphi

Parte II

Vamos criar uma classe para a aplicação. Aces-se o menu File>New>Unit – Delphi e dê o nome de “uClasse.pas”. Veja na Listagem 1 a parte inicial da nossa classe.

Listagem 1. Classe da aplicação

unit uClasse;

interface

uses Classes, SqlExpr, Provider, dbclient, DB;

type {: classe base de Cadastro } TBaseCadastro = class private FQuery: TSQLQuery; FSQLConnection: TSQLConnection; FsNmTabela: string;

FClientDataSet: TClientDataSet; public constructor Create(); destructor Destroy; override;

function Salvar(bInsert: Boolean): Boolean; function Excluir: Boolean; property Conection: TSQLConnection read FSQLConnection write FSQLConnection; property Campos: TClientDataSet read FClientDataSet write FClientDataSet; property sNmTabela: string read FsNmTabela write FsNmTabela;

end;

Page 6: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 201106

implementation

uses SysUtils;...

Veja que temos três propriedades. Connec-tion do tipo SQLConnection, responsável pelos comandos SQLs que “montaremos” para serem executados (juntamente com a variável do tipo TSQLQuery). Campos do tipo ClientDataSet é o “ca-dastro” que passaremos, por exemplo, o cadastro de clientes, passaremos o cdsCliente presente no DataModule criado anteriormente.

Por fim, temos a sNmTabela, que indicará a tabela que estamos manipulando. Essas proprieda-des devem ser configuradas antes de chamarmos os métodos Salvar ou Excluir. O Salvar recebe como parâmetro a indicação se estamos inserindo ou atualizando um registro. O Excluir, obviamente, elimina um registro no banco.

Caso queira, pode adaptar da maneira que de-sejar. Vamos entender como funciona os métodos. Primeiramente, conheceremos o Excluir, presente na Listagem 2.

Listagem 2. Método Excluir

function TBaseCadastro.Excluir(): Boolean;var sSQL: string; sNmChave, sVlChave: string; i: integer;begin

if sNmTabela = ‘’ then Exception.Create(‘Propriedade sNmTabela não definida’);

for i := 0 to Campos.FieldCount - 1 do begin //procura pelo campo chave configurado no ClientDataSet if (pfInKey in Campos.Fields[i].ProviderFlags) then begin sNmChave :=

Campos.Fields[i].FieldName; sVlChave := Campos.Fields[i].AsString; end; end;

if (sNmChave = ‘’) or (sVlChave = ‘’) then Exception.Create(‘Campo chave não encontrado’);

sSQL := ‘DELETE FROM ‘ + sNmTabela + ‘ where ‘ + sNmChave + ‘ = ‘ + QuotedStr(sVlChave);

FQuery.SQLConnection := Conection; FQuery.SQL.Clear; FQuery.SQL.Add(sSQL); Result := FQuery.ExecSQL() > 0;end;

O método verifica primeiramente se a pro-priedade sNmTabela possui algum valor e emite uma mensagem de erro caso a mesma esteja vazia. A seguir, percorremos a propriedade Campos, procurando pelos Fields configurados como chave (pfInKey).

Note que isso é extremamente importante quando configurarmos o ClientDataSet que re-torna os dados para nossos cadastros (vide artigo anterior). Precisamos configurar corretamente o ProviderFlags dos campos no ClientDataSet para que os métodos funcionem corretamente.

Após percorrer os campos, fazemos mais uma verificação para saber se foi encontrado o nome do campo chave e seu valor, para evitarmos erros na execução do SQL. Caso o código passe pela verifi-cação, montamos o SQL que executara o comando Delete no banco de dados.

A seguir, configuramos nossa variável e execu-tamos o comando no banco. O Excluir retorna um boolean para indicar se o comando foi executado com sucesso no banco. Isso ajudará para podermos retornar uma mensagem de OK para o usuário, na tela de cadastro.

Na Listagem 3 temos o método Salvar.

Listagem 3. Método Salvarfunction TBaseCadastro.Salvar(bInsert: Boolean): Boolean;var sSQLValores: string; sSQLCampos: string; sSQLWhere: string; sSQL: string; i: integer;begin

for i := 0 to Campos.FieldCount - 1 do begin //se for inserção if bInsert then begin //não adiciona a chave, pois é auto-incremento if (pfInKey in Campos.Fields[i].ProviderFlags) then Continue else sSQLValores := sSQLValores + QuotedStr(Campos.Fields[i].AsString) + ‘,’; sSQLCampos := sSQLCampos + Campos.Fields[i].FieldName + ‘,’; end else //se for atualização begin //se o campo é chave if (pfInUpdate in Campos.Fields[i].ProviderFlags) and (pfInKey in Campos.Fields[i].ProviderFlags) then sSQLWhere := Campos.Fields[i].FieldName + ‘ = ‘ + QuotedStr(Campos.Fields[i].AsString) else begin //para campos a serem atualizados

Page 7: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 2011 07

if pfInUpdate in Campos.Fields[i].ProviderFlags then begin sSQLValores := sSQLValores + Campos.Fields[i].FieldName + ‘ = ‘ + QuotedStr(Campos.Fields[i].AsString) + ‘,’; sSQLCampos := sSQLCampos + Campos.Fields[i].FieldName + ‘,’; end; end; end; end;

//remove as vírgulas (,) sSQLCampos := Copy(sSQLCampos, 0, Length(sSQLCampos) - 1); sSQLValores := Copy(sSQLValores, 0, Length(sSQLValores) - 1);

if bInsert then sSQL := ‘INSERT INTO ‘ + sNmTabela + ‘(‘ + sSQLCampos + ‘) VALUES (‘ + sSQLValores + ‘)’ else sSQL := ‘UPDATE ‘ + sNmTabela + ‘ SET ‘ + sSQLValores + ‘ where ‘ + sSQLWhere;

FQuery.SQLConnection := Conection; FQuery.SQL.Clear; FQuery.SQL.Add(sSQL); Result := FQuery.ExecSQL() > 0;end;

O método tem a mesma premissa do Excluir, percorrer o ClientDataSet, montar o SQL e executar no banco. Claro, agora temos algumas regras a serem seguidas. Primeiramente, percorremos os

campos para pegar seus nomes e valores.

Na idéia inicial, a consulta traria apenas os campos preenchidos, mas não faz sentido, pois o usuário pode estar editando um registro e resolver apagar os dados de um determinado campo. O Salvar deve persistir no banco que o campo não possui mais valor.

Continuando o código, verificamos se estamos inserindo um registro, por que o comando SQL para inserir é diferente do atualizar. Não pegamos o campo chave, por que o mesmo é auto-incremento no banco. Pegamos o valor e o campo, em variáveis distintas, separando os mesmos por vírgula (“,”). Se estivermos inserindo, apenas essas duas variáveis serão preenchidas.

Caso estejamos editando, precisamos montar o “where” da consulta. Novamente, precisamos verificar se o Field que estamos percorrendo, é uma chave, através da propriedade ProviderFlags do TField.

Assim, pegamos o nome do campo e seu valor para ser nossa condição. Se o campo não for chave, ele entrará nas variáveis para atualização. Após percorrer os campos, precisamos apenas remover as vírgulas (“,”), que ajudaram a separar os campos.

Em seguida, montamos o comando SQL de acordo com o parâmetro bInsert. Veja que o co-mando precisa ser montado corretamente, onde usamos a definição do nome dos campos no Insert, prática correta.

No Update não podemos esquecer a variável sSQLWhere que possui o nome e o valos do cam-po chave do nosso registro. Por fim, executamos o comando SQL no banco. Veja que o exemplo é simples, mas eficaz. Precisamos apenas de um componente para executar os comandos no banco e um para indicar a lista de campos que precisamos para montar o comando SQL.

Você pode adaptar a classe para a maneira que lhe convier em seus projetos. Note que a mesma é genérica, se a configuração for executada de forma correta, qualquer tabela do banco pode ser usada.

Modificando a aplicação

Precisamos agora, modificar o nosso cadastro base para executar os métodos existentes na classe. Primeiramente, declare duas variáveis na seção public do formulário:

FClasseBase: TBaseCadastro;FNomeTabela: string;

A primeira, é nossa variável da classe recém criada. A segunda será responsável por armazenar o nome da tabela que iremos executar no coman-do de Excluir e Salvar. Ela deverá ser preenchida no evento FormShow dos formulários herdados. Lembre-se bem disso, nos formulários herdados:

procedure TfrmCliente.FormShow(Sender: TObject);begin inherited; FNomeTabela := ‘CLIENTE’;end;

A FClasseBase também deve ser criada a sua instância no evento FormShow, mas no formulário base:

procedure TfrmCadastro.FormShow(Sender: TObject);begin FClasseBase := TBaseCadastro.Create;end;

Precisamos liberar da memória a instância da classe, quando fecharmos o formulário, portanto, usamos o evento FormClose:

procedure TfrmCadastro.FormClose(Sender: TObject; var Action: TCloseAction);begin FClasseBase.Free;end;

Por fim, precisamos codificar os botões de Salvar e Excluir. Na Listagem 4 vemos o código do botão Excluir.

Listagem 4. Botão Excluir do formulário base

uses uDM;...

Page 8: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 201108

procedure TfrmCadastro.ExcluirExecute(Sender: TObject);begin {: deleta se houver dados no DataSet } if (dsCadastro.DataSet.Active) and (dsCadastro.DataSet.RecordCount > 0) then begin if MessageDlg(‘Tem certeza que deseja excluir o registro ?’, mtConfirmation, [mbYes,mbNo], 0) = mrYes then begin FClasseBase.Conection := DM.SysCar; FClasseBase.sNmTabela := FNomeTabela; FClasseBase.Campos := (dsCadastro.DataSet as TClientDataSet); if FClasseBase.Excluir() then begin MessageDlg(‘Registro excluído com sucesso’, mtInformation, [mbOk], 0); dsCadastro.DataSet.Close; (dsCadastro.DataSet as TClientDataSet).Params[0].AsInteger := 0; dsCadastro.DataSet.Open; end; end; end;end;

Fazemos uma verificação se podemos excluir o registro e em seguida, pedimos a confirmação para o usuário. Após, preenchemos as propriedades e executamos o Excluir da classe. Para a propriedade Campos, fizemos um cast do ClientDataSet para a propriedade DataSet do DataSource presente no formulário base.

Assim, sabemos que em todos os formulários herdados os campos do cadastro estão presentes

nesse componente. Caso o Excluir execute correta-mente, mostramos uma mensagem ao usuário. Por fim, fechamos o componente e repassamos zero (0) para seu filtro, apenas para limpar o ClientDataSet da memória.

Veja como será fácil criarmos cadastros. Bas-tará herdar do nosso formulário base, configurar o nome da tabela e o método de exclusão esta pron-to. Na Listagem 5 temos o código do botão Salvar.

Listagem 5. Botão Salvar do formulário base

procedure TfrmCadastro.btnSalvarClick(Sender: TObject);begin {: salvo as dados se os campos estiverem preenchidos} if CamposObrigatorios (dsCadastro) and (dsCadastro.State in [dsEdit, dsInsert]) then begin FClasseBase.Conection := DM.SysCar; FClasseBase.sNmTabela := FNomeTabela; FClasseBase.Campos := (dsCadastro.DataSet as TClientDataSet); if (FClasseBase.Salvar(bFlInsert) then begin MessageDlg(‘Registro salvo com sucesso’, mtInformation, [mbYes], 0); dsCadastro.DataSet.Close; (dsCadastro.DataSet as TClientDataSet).Params[0].AsInteger := 0; dsCadastro.DataSet.Open; bFlInsert := false; end; end;end;

O código é muito semelhante a do Excluir, apenas com a diferença que chamamos o méto-

do Salvar e que verificamos antes, se os campos obrigatórios estão preenchidos, assim como se o cadastro esta sendo editado ou inserido, usando uma variável privada do tipo boolean.

A variável é configurada quando clicamos no botão Novo e quando salvamos o cadastro. No código-fonte você pode verificar onde a variável é preenchida. Caso o comando seja executado com sucesso, emitimos uma mensagem ao usuário e fechamos o cadastro, onde novamente passamos o valor “0” para o parâmetro do ClientDataSet.

Execute a aplicação e faça o teste. Adicione, atualize e exclua registros (Figura 1).

Figura 1. Manipulando o cadastro de clientes

Agora estamos prontos a criar novos cadastros em nossa aplicação. Veja na Figura 2 o cadastro de peças criado facilmente.

Figura 2. Cadastro de peças

Cadastro com consulta auxiliar

Vamos criar agora o cadastro de veículos, que também é simples, mas tem uma característica diferente da mostrada até agora. Ele possui um relacionamento com o cliente, então precisamos ter uma pesquisa auxiliar no cadastro.

Na edição de Março de 2010 da The Club, mostrei como criar um componente para consul-

Page 9: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 2011 09

tas auxiliares. Usaremos esse controle em nosso projeto. Veja na Figura 3 o cadastro em execução.

Figura 3. Cadastro de veículos com pesquisa auxiliar

A diferença fica por conta da configuração do código do cliente quando executamos o localizar. Veja na Listagem 6, o que precisamos fazer quan-do o usuário escolher um cliente no cadastro de veículos.

Listagem 6. Método para modificar o código de cliente no cadastro de veiculo

procedure TfrmVeiculo.btnPesquisarClick(Sender: TObject);begin inherited; if locCliente.Execute then begin if (dsCadastro.State in [dsEdit, dsInsert]) then begin dsCadastro.DataSet.FieldByName(‘nCdCliente’).AsInteger := locCliente.ReturnValue; DM.cdsCliente.Close; DM.cdsCliente.Params[0].AsInteger := locCliente.ReturnValue; DM.cdsCliente.Open;

edtCliente.Text := DM.cdsClientesNmCliente.AsString; DM.cdsCliente.Close; end; end;end;

Apenas verificamos se a busca retornou algum valor, e configuramos o respectivo código do cliente para o cadastro de veículos. Colocamos o nome do cliente, filtrando o ClientDataSet do cadastro de cliente para pegar seu nome e indicar o mesmo no Edit.

Veja na Figura 4 o cadastro em execução.

Figura 4. Cadastro de veículos em execução

Quando carregamos o cadastro, precisamos novamente, filtrar o nome do cliente para ser mostrado no Edit (evento DblClick do DBgrid). Para isso, usamos o código da Listagem 7.

Listagem 7. Filtrando o nome do cliente no cadastro de veículos

procedure TfrmVeiculo.DBGrid1DblClick(Sender: TObject);begin inherited;

DM.cdsCliente.Close; DM.cdsCliente.Params[0].AsInteger := dsCadastro.DataSet.FieldByName(‘nCdCliente’).AsInteger; DM.cdsCliente.Open;

edtCliente.Text := DM.cdsClientesNmCliente.AsString; DM.cdsCliente.Close;end;

Veja que as configurações extras que precisa-mos são bem fáceis de serem usadas. No próximo artigo, veremos os cadastros de Orçamento e Ordem de serviço, onde não usaremos o formu-lário base, mas poderemos usar a nossa classe de cadastro.

Conclusões

Vimos nesse artigo a criação da nossa classe para manipulação de dados no banco, apenas repassando um ClientDataSet. Com essa classe, precisamos de apenas algumas configurações para podermos ter um cadastro funcional da aplicação.

Fica a dica para você aprofundar seus conheci-mentos e quem sabe melhorar a mesma, diminuin-do a quantidade de configurações (propriedades) necessárias para a execução dos métodos Salvar e Excluir. No próximo artigo, continuaremos com nossa aplicação.

Um grande abraço a todos e até a próxima!

É Técnico em Processamento de Dados, desenvolvedor Delphi/C# para aplicações Web com ASP.NET e Windows com Win32 e Windows Forms. Palestrante da 4ª edição da Borland Conference (BorCon).

Autor de mais de 60 artigos e de mais de 300 vídeos aulas publicadas em revistas e sites especializados. É consultor da FP2 Tecnologia (www.fp2.com.br) onde ministra cursos de programação e banco de dados. É desenvolvedor da Paradigma Web Bussi-ness em Florianópolis-SC.

Sobre o autor

Luciano Pimenta

www.lucianopimenta.net

Page 10: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 201110

Neste artigo abordarei um pouco das características do SQLite, junto com alguns exemplos práticos utilizando o Android.

Uma introdução ao SQLite

SQLite é um Banco de Dados Open Source que já vem embutido no Sistema Android. É um Banco de Dados relacional suportando a sintaxe SQL, operações e instruções, requerendo pouca memória em tempo de execução. Sua estrutura está contida em apenas em um único arquivo no sistema e o acesso aos dados é implemetado por uma biblioteca de funções escritas em C.

É um gerenciador de banco de dados “auto-suficiente”, ou seja, in-dependente de uma estrutura cliente-servidor. Neste caso ele necessita de um apoio mínimo de bibliotecas externas ou até mesmo do Sistema Operacional, se tornando muito fácil para ser adaptado para o uso de dispositivos embarcados. Isto o torna flexível para muitas plataformas.

É muito utilizado em Dispositivos e sistemas embarcados (telefone celular, PDAs, MP3, entre outros), Aplicações Desktop, Sites com poucos acessos e também pode ser útil para o aprendizado.

Tipos de Campos

Na realidade no SQLite, o tipo de dado de um valor está associado com o valor propriamente dito, diferente de outros Bancos de Dados, se tornando um sistema de tipos dinâmicos.

Um campo de uma tabela em SQLite pode receber qualquer tipo de dado, ignorando o tipo informado no comando CREATE TABLE.

Em poucas palavras, podemos dizer que no SQLite existem classes de armazenamento, veja a seguir para maiores detalhes.

NULL: O campo não deve ser Nulo, característica encontrada como em qualquer outro Banco de Dados.

INTEGER: inteiro com sinal, armazenado em 1, 2, 3, 4, 6 ou 8 bytes dependendo da grandeza do valor.

REAL: valor de ponto flutuante armazenado em 8 bytes.TEXT: uma string armazenada usando UTF-8, UTF-16BE ou UTF-16LE.BLOB: armazena campos do tipo Blob.

Como posso utilizar campos do tipo Booleano e Data/Hora?

Na realidade não existe nenhuma classe do tipo Booleana, podemos considerar tipos inteiros 0 e 1, respectivamente como Verdadeiro e Falso.

É o mesmo caso para tipos de campos Data ou Hora, não existem classes para armazenamento destes tipos. O SQLite possui funções capazes de tratar os tipos citados acima.

I n t r u d u ç ã o a o A n d ro i d co m o SQLite

Page 11: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 2011 11

Funções disponíveis

Date: Retorna a data no formato YYYY-MM-DD.Time: Retorna a hora no formato HH:MM:SS.Datetime: retorna data e hora no formato YYYY-MM-DD HH:MM:SS.Strftime: retorna a data formatada de acordo com o formato especificado.

Exemplos de Utilizações

SELECT date(‘now’) – Retorna a Data Atual.SELECT time(‘now’) – Retorna a Hora Atual.SELECT datetime(‘now’) – Retorna a Data/Hora Atual.

Criando um Exemplo Básico

Seguindo os passos do artigo do mês de Novembro, teremos o Eclipse Instalado corretamente com todas as configurações prontas para o nosso exemplo. A intenção será de criar uma tela simples de inserção de dados. Para isto será necessário criar uma classe para manipulação e acesso aos dados.

Abra o Eclipse criando um novo projeto em Android, clique em File/New/Android Project. No meu caso defini como:

Project Name: TheClub_ArtigoBuild Target: Android 2.2Application Name: TheClub_ArtigoPackage Name: Pacote. TheClub_ArtigoCreate Activity: TheClub_ArtigoActivityMin SDK Version: 8

Depois de criado nosso Pacote, em Package Explorer escolha o caminho src/Pacote.TheClub e com o botão direito criaremos uma Classe, para isto basta escolher New/Class. Esta classe é responsável por trabalhar com o SQLite.

Figura 01: Criação da Classe DataHelper.

A tela acima nos proporciona realizar inúmeras atribuições na criação de uma classe, deixaremos com a seguinte configuração:

Source folder: TheClub/srcPackage: Pacote.TheClubName: DataHelperModifiers: publicSuperclass: java.lang.Object

Cheque os itens: “Inherited abstract methods“ e “Generate comments” para podermos herdar os métodos abstratos e gerar comentários respectiva-mente. Veja abaixo o código gerado:

package Pacote.TheClub;/** * @author Thiago * */public class DataHelper {}

Implementando uma Classe de Dados

Nos próximos passos irei criar a classe e darei uma breve explicação do código. Primeiramente utilizaremos o comando “import” para nos dar acesso a algumas classes necessárias para o funcionamento e em seguida definir alguns atributos necessários.

import android.content.Context;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;import android.database.sqlite.SQLiteStatement;import android.util.Log;import java.util.ArrayList;import java.util.List; ..private static final String DATABASE_NAME = “DB_THECLUB.db”;private static final int DATABASE_VERSION = 1;private static final String TABLE_NAME = “TB_CLIENTE”;private Context context;private SQLiteDatabase db;private SQLiteStatement insertStmt;private static final String INSERT = “insert into “ + TABLE_NAME + “(name) values (?)”;

Page 12: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 201112

Notem que estes atributos são do tipo “private”, ou seja, são utilizáveis apenas dentro de nossa classe DataHelper.

Logo em seguida programaremos o método Construtor recebendo como parâmetro um Contexto de informações e mais abaixo Implementamos o Método “insert” para inserir dados, “deleteAll” para exclusão, “selectAll” para consultas e por final incluímos uma inner-classe importante que nos dá acesso a um SQLiteOpenHelper.

public DataHelper(Context context) { this.context = context; OpenHelper openHelper = new OpenHelper(this.context); this.db = openHelper.getWritableDatabase(); this.insertStmt = this.db.compileStatement(INSERT); } public long insert(String name) { this.insertStmt.bindString(1, name); return this.insertStmt.executeInsert(); }

public void deleteAll() { this.db.delete(TABLE_NAME, null, null); }

public List<String> selectAll() { List<String> list = new ArrayList<String>(); Cursor cursor = this.db.query(TABLE_NAME, new String[] { “cod_cli”, “nom_cli” }, null, null, null, null, “cod_cli”); if (cursor.moveToFirst()) { do { list.add(cursor.getString(0) +” - “ + cursor.getString(1)); } while (cursor.moveToNext()); } if (cursor != null && !cursor.isClosed()) { cursor.close(); } return list; }

private static class OpenHelper extends SQLiteOpenHelper

{ OpenHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); }

@Override public void onCreate(SQLiteDatabase db) { db.execSQL(“CREATE TABLE “ + TABLE_NAME + “(cod_cli INTEGER PRIMARY KEY, nom_cli TEXT)”); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.w(“Example”, “Upgrading database, this will drop tables and recreate.”); db.execSQL(“DROP TABLE IF EXISTS “ + TABLE_NAME); onCreate(db); } }

Uma informação para quem não sabe, Inner Class são classes internas declaradas dentro de outras classes.

Percebam que criamos uma tabela de clientes com apenas dois campos para nosso artigo, mas com certeza este exemplo cobre todos os conceitos básicos de manipulação de dados do Android. Não entraremos em muitos detalhes em relação a esta classe.

Criando um layout de Cadastro

Para isto navegue até o caminho res/layout/main.xml e na Paleta “Form Widgets “ adicione um TextView, um Button e um EditText da paleta “Text Fields”.

Defina suas propriedades em seguida como:

TextView1Id: @+id/textView1 Text: Nome:Layout Height: wrap_contentLayout Width: wrap_contentEditText1Id: @+id/editText1 Input type: textPersonNameLayout Height: wrap_contentLayout Width: wrap_contentButton1Id: @+id/button1 Text: InserirLayout Height: wrap_contentLayout Width: 104dp

Page 13: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 2011 13

Figura 02: Layout da Tela.

O arquivo de layout main.xml ficou da seguinte maneira:

<?xml version=”1.0” encoding=”utf-8”?><ScrollView xmlns:android=”http://schemas.android.com/apk/res/android” android:layout_width=”fill_parent” android:layout_height=”wrap_content”> <LinearLayout xmlns:android= “http://schemas.android.com/apk/res/android” android:orientation=”vertical” android:layout_width=”fill_parent” android:layout_height=”19dp” android:weightSum=”1”> <TextView android:id=”@+id/textView1” android:layout_width=”wrap_content” android:layout_height=”wrap_content” android:text=”Nome:”></TextView> <EditText android:layout_height=”wrap_content” android:id=”@+id/editText1” android:inputType=”textPersonName” android:layout_width=”300dp”> </EditText> <Button android:text=”Inserir” android:id=”@+id/button1” android:layout_height=”wrap_content” android:layout_width=”104dp”></Button> <TextView android:id=”@+id/out_text” android:layout_width=”fill_parent” android:layout_height=”wrap_content” android:text=”” /> </LinearLayout></ScrollView>

É interessante observar que o trecho do código abaixo foi adicionado para exibir a saída dos dados cadastrados.

..<TextView android:id=”@+id/out_text” android:layout_width=”fill_parent” android:layout_height=”wrap_content” android:text=”” />

A Figura 03 ilustra nossa tela em Run-Time.

Figura 03: Tela de Cadastro.

Codificando o Botão Inserir

Primeiramente localize a classe “TheClubActivity” em src/Pacote.TheClub e logo em seguida adicionaremos algumas classes, veja abaixo:

import Pacote.TheClub.DataHelper;import Pacote.TheClub.R;import android.app.Activity;import android.app.AlertDialog;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import java.util.List;

Definimos alguns atributos, como:

TextView saida;DataHelper db;Button btn1;EditText edt1;

Page 14: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 201114

E no método OnCreate programaremos o seguinte código

public void onCreate(Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView(R.layout.main); btn1 = (Button) findViewById(R.id.button1); saida = (TextView) this.findViewById(R.id.out_text); db = new DataHelper(this); edt1 = (EditText) findViewById(R.id.editText1); btn1.setOnClickListener(new View.OnClickListener() {@Override public void onClick(View v) { db.insert(edt1.getText().toString()); List<String> names = db.selectAll(); StringBuilder sb = new StringBuilder(); sb.append(“Clientes Cadastrados:\n”); for (String name : names) { sb.append(name + “\n”); } saida.setText(sb.toString()); } });}

No código acima estamos usando o método “findViewById”, que tem como objetivo atribuir o objeto da tela pelo localizado pelo Id a uma variável do mes-mo tipo. Desta forma conseguimos manipular toda informação ali trabalhada.

Para utilizar a classe criada anteriormente devemos instanciá-la como um objeto qualquer passando o parâmetro “this” que seria o contexto em geral da aplicação. Veja abaixo novamente:

db = new DataHelper(this);

Utilizamos o Método OnClick do Botão para Inserir os Dados com o método db.Insert e selecioná-los em seguida com o db.SelectAll. A Classe StringBuilder serve para armazenar os registros e mostrá-los na tela.

Figura 04: Dados Inseridos no SQLite.

Observem que a Classe DataHelper possui o método DeleteAll que não foi utilizado especificamente neste artigo. Os métodos criados podem e devem ser melhorados de acordo com a necessidade do sistema. Uma dica seria criar um Método que Excluísse apenas um registro passado por parâmetro, ou criar um que selecionasse apenas um registro para mostrar na tela. Fica aí a dica.

Conclusões

Podemos dividir este artigo em duas partes, a primeira como uma teoria destacando informações e dicas referentes ao SQLite do Android e a segunda uma prática com um exemplo simples utilizando a linguagem Java para tra-balhar com dados.

A linguagem Java nos proporciona um leque de aprendizado, é um prato cheio para quem está aprendendo Orientação a Objetos pelo fato de ser totalmente desta maneira.

Espero que este artigo proporcione aos senhores um pontapé inicial para trabalhar com a Tecnologia Android.

Um Forte abraço e até o mês que vem!

Referências

http://www.sqlite.org/datatype3.htmlhttp://www.screaming-penguin.com

Thiago Cavalheiro Montebugnoli é tecnólogo, formado pela Faculdade de Tecnologia de Botucatu – SP (FATEC) foi consultor técnico do The Club, já desenvolveu softwares utilizando a plataforma .NET, Delphi junto com Banco de Dados SQL Server e Firebird. Atualmente trabalha no Centro de Proces-samento de Dados da Prefeitura Municipal de Itaí-SP. Possui as seguintes certificações: MCP - Microsoft Certified Professional, MCTS - Microsoft Certi-fied Technology Specialist, MCAD - Microsoft Certified Application Developer e MCSD - Microsoft Certified Solution Developer.

Sobre o autor

Thiago Cavalheiro Montebugnoli

[email protected]

Page 15: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 2011 15

Quando se trabalha com transferências de arquivos em aplicativos, sejam feitos em Delphi ou outras ferramentas, as vezes é ne-cessária a compressão desses arquivos para aumentar a performance.

Comprimir um arquivo é codificá-lo em outro padrão para reduzir seu volume na memória do computador.

Atualmente existem vários padrões de compressão de arquivos. O mais conhecido em ambiente Windows sem dúvida é o .zip. Semelhante ao .zip temos o .rar. Tanto os formatos zip quanto rar criam uma pasta compactada que contém os arquivos origi-nais. Esse formato de pasta facilita a des-compressão dos arquivos já que a estrutura de diretórios é bem familiar aos usuários da

Streams e compressão de arquivos com ZipMaster em Delphi

plataforma Windows.

Ainda no assunto de padrões de compres-são, um padrão bem conhecido e que muitos não sabem que se trata de um formato com-primido são os arquivos com a extensão .iso. Esses arquivos são muito populares quando temos a gravação de CD’s e DVD’s, pois em geral as imagens das mídias na pré-gravação estão comprimidas em formato .iso.

Na área de multimídia, temos o também bastante conhecido padrão .mp3. O mp3 é um arquivo de áudio do qual são elimina-das frequências ou faixas de frequências desnecessárias. Isso torna o arquivo menor. O formato mp3 se tornou muito popular a partir da expansão do compartilhemento de músicas via internet.

O formato .mp4 é bem semelhante ao .mp3, porém foi desenvolvido para suportar arquivos de vídeo. No formato .mp4, os vídeos ocupam um espaço bem menor se comparado aos formatos tradicionais como .wmv e .avi. É claro que tanto a compressão no s formatos .mp3 como .mp4 implicam em alguma perda de qualidade, porém o ganho em espaço e performance nas transferências acaba por justificar a adoção desses formatos em muitos casos.

Claro que para trabalharmos com com-pressão de arquivos, precisamos de progra-mas que façam o trabalho de comprimir. Em ambiente Windows, sem dúvida os programas mais utilizados hoje são o Winrar e WinZip. O Winrar se caracteriza por trabalhar com vários formatos, além de possuir ferramentas que

Page 16: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 201116

permitem criar pastas auto-extraíveis, muito úteis em instaladores que apenas necessitam fazer cópias para uma pasta em específico, como é o caso dos famosos SDK’s, ou kits de desenvolvimento de softwares. Além disso, com o Winrar podemos separa arquivos muito grandes em partes durante a compressão.

Além dos programas que trabalham com compressão de arquivos, em algumas situações necessitamos comprimir arquivos diretamente em nossas aplicações Delphi. É dessa forma de compressão que falaremos nesse artigo.

Quando trabalhamos com compressão de dados, consequentemente temos de tra-balhar com arquivos e em Delphi a classe que manipula arquivos é a Tstream. Um stream representa um fluxo de dados, com tamanho definido. Quando trabalhamos com a classe Tstream e suas descendentes, precismos ter em mente que sempre estaremos em algum ponto definido, representado por um cursor. A lógica é semelhante a compararmos o Stream como um disco e esse cursor seria a agulha de leitura desse disco. Nas transferências de arquivos, o cursor vai realizando a leitura do Stream que contém o arquivo bit a bit até completar o tamanho do arquivo.

A classe Tstream dificilmente é utilizada

em Delphi. No lugar da mesma, são utilizadas suas descendentes. Essas classes descenden-tes possuem cada uma uma especialidade, sendo utilizadas para situações específicas.

Vejamos quais são as pricipais descendentes de TStream:

TStringStream – Essa classe trabalha com strings, armazenando as mesmas para que possam ser manipuladas como arquivos. Essa classe é muito útil em descargas de dados provenientes da Web, como na implementação da Nota Fiscal Eletrônica, onde necessitamos enviar o xml e recebê-lo em formato de string.

TFileStream – Para nosso artigo, é o descen-dente mais relevante. É através de TFileStream que abrimos e manipulamos arquivos nos mais

diversos formatos. Para a compressão de dados, TfileStream é melhor pois podemos trabalhar com a mesma independente do formato de arquivo que será compactado.

TBlobStream – Quando se trabalha com ar-mazenamento de dados binários direto no banco de dados, é importante que possamos recuperar os dados da forma mais “limpa” possível, eviatndo discrepâncias. A classe TblobStream possui justa-mente como especialidade trabalhar com dados provenientes de campos binários em datasets. Através de TblobStream podemos tanto trazer como enviar dados binários para o dataset e depois ao banco de dados.

TWinSocketStream – Esse formato é especia-lizado para a troca de informações via sockets. É bem pouco utilizado.

TOleStream – Stream para manipulação de dados provenientes de objetos OLE. A tecnologia OLE (Object Linking and Embeding) é o que permite a troca de dados entre diferentes aplicações em ambiente Windows, como por exemplo quando recortamos um texto do navegador de internet e colamos o mesmo no editor de textos. Em Delphi temos objetos para o trabalho com a tecnologia OLE e ToleStream pode ser um excelente aliado na manipulação desses objetos.

Salvando componentes no Stream

Quando falamos dos dados manipulados pela classe TStream e suas descendentes, não precisa necessariamente ser dados provenientes de um arquivo. Podemos trabalhar com qualquer tipo de dado. Até mesmo componentes do Delphi podem ser salvos através de Streams.

Veja o exemplo abaixo:

procedure SalvaComponente;// Essa procedure carrega o componente// para dentro de um stream e salva// o componente em arquivovar stListBox:TFileStream;begin

try stListBox:=TFileStream.Create(‘c:\minhalista.dat’,fmOpenReadWrite); stListBox.WriteComponent(ListBox1); finally stListBox.Free end;end;

procedure CarregaComponente;// Aqui recuperamos o componente salvo anteriormentevar stListBox:TFileStream;begin if(FileExists(‘c:\minhalista.dat’))then try stListBox:=TFileStream.Create(‘c:\minhalista.dat’,fmOpenReadWrite); stListBox.ReadComponent(ListBox1); finally stListBox.Free end;end;

Como vimos, armazenar um componente em um arquivo e depois recuperá-lo através dos Streams não é nada complexo. E além de simples, essa prática pode ser muito útil.

Manipulando Imagens com TStream

Em Delphi, um dos grandes usos da classe Tstream é para a manipulação de imagens. Entre esses usos, podemos citar a conversão de imagens.

O exemplo que faremos a seguir faz uso de Tstream para converter um bitmap para o formato Jpeg.

O layout da aplicação será composto de dois componentes Image; Dois componentes Button

Page 17: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 2011 17

além de duas labels.

Veja a imagem 01 do Layout: Agora o código do exemplo.

unit Unit1;

interface

uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs,Jpeg, StdCtrls, ExtCtrls;

type TForm1 = class(TForm) Image1: TImage; Label1: TLabel; Label2: TLabel; Image2: TImage; btnSalvarJpeg: TButton; btnCarregarImagem: TButton; Label3: TLabel; Label4: TLabel; procedure btnCarregarImagemClick (Sender: TObject); procedure btnSalvarJpegClick (Sender: TObject); private { Private declarations } public { Public declarations } end;var Form1: TForm1;procedure ConverteBMPparaJPG (Instream: TStream);

implementation

{$R *.dfm}

procedure ConverteBMPparaJPG (Instream: TStream);

var JpegImage: TJpegImage; Bitmap: TBitmap;begin

JpegImage := TJpegImage.Create; Bitmap := TBitmap.Create; try // Carrega e exibe a imagem Bitmap Bitmap.LoadFromStream(InStream); Form1.Image1.Canvas.Draw(0,0,Bitmap); Form1.Label1.Caption := ‘Imagem Bitmap’;

// Converte para Jpeg JpegImage.Assign(Bitmap); Form1.Image2.Canvas.Draw (0,0,JpegImage); Form1.Label2.Caption := ‘Imagem Jpeg’; finally JpegImage.Free; Bitmap.Free; end;

end;

procedure TForm1.btnCarregarImagemClick

(Sender: TObject);var InStream: TFileStream;begin try //Salvamos o bitmap como Jpeg através da conversão InStream := TFileStream.Create (‘imagem.bmp’,fmOpenRead); ConverteBMPparaJPG (Instream); finally InStream.Free; end;

end;

procedure TForm1.btnSalvarJpegClick (Sender: TObject);var OutStream: TFileStream; JpegImage: TJpegImage;begin // Salvamos o Jpeg anteriormente criado na conversão JpegImage := TJpegImage.Create; JpegImage.Assign (Image2.Picture.Bitmap); try OutStream :=

Imagem 01

Page 18: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 201118

TFileStream.Create (‘imagem.jpg’,fmOpenWrite or fmCreate); JpegImage.SaveToStream (OutStream); finally OutStream.Free; JpegImage.Free; end;

end;

end.

Compressão de arquivos e diretórios com ZipMaster

Vamos agora trabalhar com a compressão de arquivos. O Delphi possui uma bibloteca nativa para compressão de arquivos, chamada Zlib. Além dessa biblioteca , existem componentes de terceiros que realizam compressão de dados, como o ZipForge e o ZipMaster. É o componente ZipMaster que abordaremos na sequência.

O download do componente ZipMaster pode ser realizado no seguinte endereço:

http://www.delphizip.org/download/zm-190setup0116.zip.

Após o download, extraia e execute o insta-lador. Será solicitada uma pasta de destino. Essa pasta é importante porque é nela que estará a package para instalação após o termino da execu-ção do instalador.

O componente ZipMaster é compatível com diversas versões do Delphi, como podemos ver na pasta Delphi dentro do diretório de instalação:

Veja a imagem 02.

Para adicionar o componente a IDE do Delphi, abra a dpk correspondente a versão do Delphi, compile e depois instale. Será criada a aba Delphi-Zip19 na IDE do Delphi.

Após a instalação, estamos aptos a criar nosso primeiro exemplo com o ZipMaster.

Inicie uma nova aplicação no Delphi e adicione

duas Edits, dois Buttons, além do componente ZipMaster.

O layout deverá ficar como na imagem 03:

No evento Onclick do botão “Selecionar Ar-quivo”, faça:

procedure TForm1.Button1Click(Sender: TObject);begin

Imagem 02

with TOpenDialog.Create(nil) do try

if(Execute)then edtArquivoSelecionado.Text:=FileName;

finally Free; end;end;

Imagem 03

Page 19: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 2011 19

E no OnClick do botão “Comprimir com Zip-Master”, faça:

procedure TForm1.Button2Click(Sender: TObject);begin ZipMaster191.FSpecArgs.Add(edtArquivoSelecionado.Text);

with TSaveDialog.Create(nil) do try if(Execute)then begin ZipMaster191.ZipFileName:=FileName; ZipMaster191.Add; end; finally lblMensagem.Caption:=’Concluído !’; Free; end;

end;

Veja o exemplo em execução na imagem 04:

Podemos utilizar o componente ZipMaster na compactação de não apenas um arquivo mas também de todo um diretório.

Para compactarmos um diretório, não utili-zaremos o OpenDialog mas em seu lugar o Direc-toryOutline da aba Samples. O procedimento de compactação é bem semelhante ao que fizemos há pouco. Nesse procedimento, vale lembrar que a estrutura interna da pasta, caso a mesma contenha subpastas será mantida.

Veja o código a seguir:

procedure TForm1.Button3Click(Sender: TObject);begin

ZipMaster191.FSpecArgs.Add(DirectoryOutline1.Directory);

with TSaveDialog.Create(nil)do try

if(Execute)then begin ZipMaster191.ZipFileName:=FileName; ZipMaster191.AddOptions:=ZipMaster191.AddOptions+ [AddDirNames, AddRecurseDirs];

ZipMaster191.Add; end; finally ZipMaster191.FSpecArgs.Clear; Free; end;

end;

Em todos os exemplos, o formato de saída das compressões será .zip, o que irá facilitar a posterior leitura desses arquivos por outros programas na plataforma Windows.

Após compactarmos o diretório, podemos utilizar o ZipMaster para exibir o conteúdo do

Imagem 04

Imagem 05

Page 20: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 201120

arquivo Zip.

É o que faremos no exemplo a seguir.

Crie uma nova aplicação no Delphi e monte o layout conforme a imagem 05:

Essa aplicação será utilizada para carregarmos um arquivo .zip e listar quais arquivos compoem o mesmo no ListBox. Essa listagem é proporcionada pelo componente ZipMaster.

Veja que temos apenas um botão no exemplo. É nele que ficará todo o código necessário, que é bem simples.

Inicialmente criaremos um OpenDialog filtrado para exibir somente arquivos .zip.

No execute desse OpenDialog pegaremos o caminho do arquivo .zip e carregaremos o mesmo no componente ZipMaster. Após isso listaremos os arquivos no componente ListBox.

Veja o código:

procedure TForm1.Button1Click(Sender: TObject);var i:integer; sFileName:string;begin listboxarquivos.Items.Clear;

with TOpenDialog.Create(nil)do try Filter:=’Zip Files|*.zip’;

if(Execute)then sFileName:=FileName; finally Free; end;

edtArquivo.Text:=sFileName;

ZipMaster191.ZipFileName:=sFileName; for i:=0 to ZipMaster191.Count-1 do listboxarquivos.Items.Add(ZipMaster191[i].FileName);

end;

Veja o aplicativo em execução na imagem 06:

Imagem 06

Conclusão

Vimos neste artigo que Streams e o compo-nente ZipMaster podem ser excelentes aliados em nosso dia a dia quando necessitamos trabalhar com arquivos. Tanto nos casos de transferências dos mesmos como para operações mais complexas como conversões.

Por enquanto é isso. Até a próxima !

Consultor Técnico The Club.

Sobre o autor

Antonio Spitaleri Neto

[email protected]

Page 21: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 2011 21

Page 22: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 201122

MÉTODOS RAVEReportde A a Z

PPRINT IMAGE RECT – Este método vai

chamar ImageStream na tela da impressora, esticado ou encolhido para caber dentro do retângulo definido pelos pontos (X1, Y1) e (X2, Y2).

Example (Delphi)

with Sender as TBaseReport do beginStream := TMemoryStream.Create;Image := TJPEGImage.

Create;try Image.LoadFromFile(‘image1.jpg’); Image.SaveToStream(Stream); Stream.Position := 0; PrintImageRect(1,1,3,3,Stream,’JPG’);finally Image.Free; Stream.Freeend; {tryf}end; {with}

PRINT JUSTIFY – Este método impri-me à esquerda, direita, centro ou bloco de texto justificado. O texto deve ser justificado

dentro de um retângulo de medição a partir de Pos e com um tamanho horizontal de lar-gura. A margem é o espaço entre o texto e os lados do retângulo de medição em unidades.

Example (Delphi)

PrintJustify(‘Centered Text’, SectionLeft,pjCenter,0.0,SectionRight - SectionLeft);{ Same as PrintCenter(‘Centered Text’, (SectionLeft + SectionRight) / 2.0); }

PRINT LEFT – este método imprime

Page 23: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 2011 23

a strint Texto na linha atual, justificado à esquerda, na posição POS.

Example (Delphi)

RvNDRWriter1.PrintLeft( ‘Text left at 4.0’, 4.0);

PRINT LINES – Esse método imprime o buffer de memória para o número de linhas especificadas por Lines. Se Lines é 0, então to-das as linhas no buffer nota serão impressas. Se PrintTabs for verdadeiro, então PrintMemo vai imprimir as linhas de guias em branco para cada linha que o buffer de memória imprime.

Nota: se todo o buffer de memória não é impresso, a posição interna de MemoBuf será definida para o último caractere que foi impresso. Isso permitirá que o buffer de memoria seja continuado em outra página.

Nota: deve-se inicializar o TMemoBuf.BaseReport antes de chamar esse método

PRINT LN – este método imprime a string Texto da mesma forma que o método Print faz, porém ele também chama NewLine para ir para a próxima linha.

Example (Delphi)

RvNDRWriter1.Println( ‘Text on a line’);RvNDRWriter1.PrintLn( ‘Text on another line’);

PRINT MEMO – este método impri-me o buffer de memória, MemoBuf, para o número de linhas especificado por Lines. Se Lines é 0, então todas as linhas do buffer de memória serão impressas. Se PrintTabs é verdadeiro, então PrintMemo imprime linhas

de tabs vazias para cada linha que o buffer de memória imprime.

Example (Delphi)

SetColumns(3,0.25);MemoBuf.PrintStart := ColumnStart;MemoBuf.PrintEnd := ColumnEnd;PrintMemo(MemoBuf, ColumnLinesLeft, false);ClearColumns;

PRINT PAGE – este método imprime a página especificada pelo PageNum para a janela de pré-visualização. O evento OnPa-geChange é chamado se mudar o número atual de páginas.

Example (Delphi)

RvRenderPreview1.PrintPage( 2);

PRINT RIGHT – este método imprime a string Texto na linha atual, justificada à direita, na posição Pos.

Example (Delphi)

RvNDRWriter1.PrintRight(‘Right justified at 3.0’,3.0 );

PRINT TAB – Este método de imprime a configuração de tabulação seguinte e, em seguida, imprime texto dentro dessa caixa de guia. Isso é equivalente a impressão (# 9 + texto), com a ressalva de que, se for muito longo, oTexto é truncado.

Example (Delphi)

PrintTab(FieldByName (‘Name’));

PRINT X,Y – este método imprime a string Texto no local especificado pelo ponto (X,Y).

Nota: a posição Y determina o local da linha de base do texto impresso.

Example (Delphi)

RvNDRWriter1.PrintXY( 1.0, 2.0, ‘Text above (1.0, 2.0)’);

PUSH FONT – Este método empurra a fonte atual para uma pilha interna para posterior recuperação pelo PopFont

PUSH POS – este método empurra a posição atual do cursor de texto para uma pilha interna para posterior recuperação pelo PopPos.

PUSH TABS – Este método empurra as configurações da guia atual em uma pilha interna para posterior recuperação pelo PopTabs.

R

Page 24: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 201124

RECOVER PRINTER – Este método recupera o identificador de impressora que foi perdido por uma chamada anterior ao método ReleasePrinter.

RECTANGLE – este método desenha um retângulo definido pelos pontos (X1, Y1) E (X2, Y2).

O retângulo é desenhado com uma borda da caneta atual e preenchido com o pincel atual.

Example (Delphi)

RvNDRWriter1.Rectangle(1.0, 1.0, 4.0, 5.0);

REDRAW PAGE – este método re-desenha a página atual para uma tela de pré-visualização.

Example (Delphi)

RvRenderPreview1.RedrawPage;

REGISTER GRAPHIC – Este método vai ajudar a gerenciar a repetição de bitmaps grandes em um trabalho de impressão. Pode--se registrar até 10 bitmaps de uma só vez, passando o valor do índice de 1 para 10. Com este método, apenas uma cópia do bitmap é armazenado no arquivo com todas as outras funções de impressão fazendo referência à mesma cópia.

Nota: Use UnregisterGraphic (n) para se certificar de que o índice de gráfico que você está usando está limpo.

Nota: Este método só vai otimizar a exe-

cução de um relatório através TRvNDRWriter.

Example (Delphi)

Bitmap := TBitmap.Create;with Sender as TBaseReport do tryBitmap.LoadFromFile( ‘LOGO.BMP’ );UnregisterGraphic( 1 );while not Table1.EOF do begin ReuseGraphic( 1 ); PrintBitmapRect( 1,1,2,2,Bitmap ); RegisterGraphic( 1 ); { other printing code }end; { while }finally Bitmap.Free;end; { with }

RELEASE PRINTER – Este método

libera o identificador de impressora do Rave, para que outros componentes, tais como TPrinterSetupDialog, possam acessar a impressora. Usar RecoverPrinter para re--inicializar o Rave e recuperar o identificador de impressora.

Example (Delphi)

RvNDRWriter1.ReleasePrinter;PrinterSetupDialog1.Execute;RvNDRWriter1.RecoverPrinter;

REPLACE ALL – Este método substitui todas as ocorrências de SearchText com Re-placeText. Se CaseMatters for verdadeiro, en-tão o caso dos caracteres deve corresponder.

Example (Delphi)

MemoBuf.ReplaceAll(‘ame, Name, false);MemoBuf.ReplaceAll(‘ddress, Address, false);

REPORT DESC TO MEMO – inicializa o componente Memo para o conteúdo atual do relatório selecionado.

RESET – este método retorna certas configurações (pena, pincel, origens, colunas, tabs, sections e posição do cursor) para seus valores padrão.

Example (Delphi)

RvNDRWriter1.Reset;

RESET LINE HEIGHT – Este método redefine a propriedade LineHeight para a fonte atual se a propriedade LineHeight-Method é igual a lhmFont. Caso contrário, ResetLineHeight configura LineHeight para o valor de 1,0 LinesPerInch ou deixá-lo sozinho se LineHeightMethod é lhmUser.

Example (Delphi)

RvNDRWriter1.ResetLineHeight;

RESET PRINTER – Este método irá redefinir a impressora atual para as definições dadas na estrutura DevMode bem como ou-tras configurações da impressora. Essa função é chamada automaticamente sempre que for alterada a impressora atual ou alterada a orientação.

Page 25: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 2011 25

Example (Delphi)

RvNDRWriter1.ResetPrinter;

RESET SECTION – Este método re-define os valores de seção, SectionLeft, Sec-tionRight, SectionTop e SectionBottom para ser igual às configurações de margem atual.

Example (Delphi)

RvNDRWriter1.ResetSection;

RESET TABS – Este método redefine a guia atual para o começo. NewLine chama essa função para redefinir a guia atual.

Example (Delphi)

RvNDRWriter1.ResetTabs;

RESTORE BUFFER – este método restaura o buffer de memória para o estado em que estava durante a última chamada do SaveBuffer.

RESTORE FONT – Este método restau-ra as configurações de fonte, salvo por uma chamada anterior a SaveFont, usando um índice de 1 a 10. O resultado desta função será verdadeiro se a chamada for bem-sucedida.

Example (Delphi)

// Restaura a fonte salva na posição 10.RestoreFont(10);

RESTORE POSITION – Este método define a posição do cursor de texto para a configuração que foi armazenada por último no índice Índice, pelo SavePos. Os valores válidos para índice são de 1 a 10.

Example (Delphi)

RvNDRWriter1.RestorePos(1);

RESTORE STATE – Este método restau-ra a posição do cursor e outras informações de estado do buffer de memória de volta ao que era quando SaveState foi chamado.

Nota: Isso não afeta o conteúdo do buffer de memória.

RESTORE TABS – Este método restau-ra as configurações da guia, salvas por uma chamada anterior a SaveTabs, usando um índice 1-10. O resultado desta função será verdadeiro se a chamada for bem-sucedida.

Example (Delphi)

// Restaure as configurações da tab na posição 3. RestoreTabs(3);

REUSE GRAPHIC – este método per-mite o uso de um bitmap grande e repetido em uma impressão que tenha sido registrada com o método RegisterGraphic. Com este método, somente uma cópia do bitmap será armazenada no arquivo com todas as outras funções de impressão referentes à mesma cópia.

Nota: este método somente otimiza a execução de um relatório através de TRvN-DRWriter.

ROUND RECT – este método desenha um retângulo definido pelos pontos (X1,Y1) e (X2,Y2). Os cantos do retângulo serão dese-nhados como quartos de uma elipse com uma largura de X3 e uma altura de Y3. O retângulo será desenhado com uma borda da caneta atual e preenchido com o pincel atual.

Example (Delphi)

RoundRect 1.125,3.5,3.125,5. 0,0.25,0.25);

RTF LOAD FROM FILE – carrega um arquivo de texto RTF para o buffer de memória.

Example (Delphi)

MemoBuf1.RTFLoadFromFile( ‘Letter.RTF’);

RTF LOAD FROM STREAM – Carrega um texto RTF de um processo para o buffer de memória. Se BufSize é 0 então o comprimento restante do processo é lido, caso contrário, BufSize bytes é que são lidos.

SAVE – este método salva o projeto atual para o arquivo especificado pela pro-priedade ProjectFile.

SAVE BUFFER – este método salva o buffer de memória atual para um buffer salvo que pode ser recuperado mais tarde com Res-toreBuffer. Pode ser útil para imprimir cartas que se deseja modificar em cada impressão, mas que se deseja retornar às configurações originais no início de cada página.

Page 26: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 201126

Consultora Técnica The Club.

Sobre o autor

Leonora Golin

[email protected]

Example (Delphi)

// Salva conteúdo original. MemoBuf.SaveBuffer;

SAVE FONT – este método salva as configurações atuais de fonte utilizando um valor de índice de 1 a 10. Estas configurações podem ser restauradas mais tarde, por uma chamada ao método RestoreFont. O resultado desta função será true se a chamada foi bem sucedida.

Example (Delphi)

// Salva as configurações de fonte atuais na posição 2. SaveFont(2);

SAVE POS – este método armazena a posição atual do cursor de texto em um array de índices, Index. Os valores válidos são de 1 a 10.

Example (Delphi)

RvNDRWriter1.SavePos(1);

SAVE RAVE BLOB – Este método salva o projeto do relatório atualmente carregado a partir do formulário da aplicação para Stream. Não é preciso chamar essa função uma vez que o método normal de salvar o projeto do relatório carregado é feito através do editor de propriedades TRvProject.StoreRAV.

Example (Delphi)

RvProject1.SaveRaveBlob( MyStream );

SAVE STATE – este método salva a posi-ção atual do cursor, Pos, e outras informações de estado. Pode-se restaurar o estado anterior do buffer de memória, chamando o método RestoreState.

SAVE TABS – este método limpa as configurações atuais de tabulação assim como todas as salvas. Não é necessário fazer a chamada a este método uma vez que as tabulações são limpas assim que o relatório esteja terminado.

Example (Delphi)

// Limpar todas as tabulações, inclusive as salvas. ClearAllTabs;

SAVE TO FILE – este método salva o projeto de relatório em um arquivo especifi-cado pelo FileName.

Example (Delphi)

RvProject1.SaveToFile(‘Project1.Rav’);

SAVE TO STREAM – este método salva o buffer de memória para o processo.

Example (Delphi)

MemoBuf1.SaveToStream( MyStream );

SEARCH FIRST – Este método inicia um processo de pesquisa, procurando SearchText desde o início do buffer. Se CaseMatters for verdadeiro, então o caso dos caracteres deve corresponder, de outra forma, o caso não será um fator para combinar. Esta função irá retornar true se ele encontrar uma corres-pondência e false, se não. Usar SearchNext para continuar a pesquisa após a primeira ocorrência.

Example (Delphi)

// Armazena o número de ocorrências de ‘APPLES’ in apples Apples := 0;Found := MemoBuf.SearchFirst(‘APPLE’, false);while Found do beginInc(Apples);Found := MemoBuf.SearchNext;end; { while }

Page 27: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 2011 27

Page 28: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 201128

Dicas DELPHI

Criptografando dados de arquivos

Um recurso pra quem precisa utilizar arquivos externos e deseja protegê--los de usuários indevidos é a criptografia de dados e registros. São conhecidas muitas maneiras de se criptografar, porém algumas mais eficientes outras nem tanto, uma referencia são os modelos de criptografia que seguem padrões específicos, o MD5 e o SHA1, que tratam exclusivamente de criptografia de registros, convertendo os dados em uma sequencia numérica padrão, mas o grande problema dos sistemas criptografadores são que seus registros reais se tornam não-identificáveis pelo método tradicional de leitura, dependendo de seu método criptografado para que possa ser lido, o que causa muitos transtornos caso haja perda ou troca de senha.

Essa dica é útil para transferência de registros que precisam estar ocultos e invioláveis, onde é transformado todo e qualquer caractere conhecido em linhas não interpretáveis.

O primeiro passo é declarar a procedure que terá como parâmetro de en-trada o arquivo de entrada e o de saída, sendo do tipo String e a chave (do tipo Word), que servirá como controle para geração da quantidade de caracteres criptografados a partir dos arquivos de entrada e saída.

procedure TForm1.Encriptar(arqEntrada, arqSaida: String; Chave: Word);

Declaramos também 4 variáveis, sendo duas do tipo MemoryStream, que servirão de para o controle de entrada e saída, além de uma do tipo Inteira, que servirá como contadora e outra do tipo Byte, que armazenará os valores criptografados.

var msEntrada, msSaida : TMemoryStream; I : Integer; C : byte;

O primeiro passo é inicializar as duas variáveis do tipo MemoryStream, e na variável que recebera os registros de entrada, carregamos o arquivo informado no parâmetro para entrada e deixando na posição 0.

begin msEntrada := TMemoryStream.Create;

msSaida := TMemoryStream.Create; try msEntrada.LoadFromFile(arqEntrada); msEntrada.Position := 0;

Agora é necessário que seja realizado um loop de controle para que seja verificado o tamanho do valor de memória, onde será lido o valor em memória, convertendo os caracteres para valores chave e escrevendo no MemoryStream de saída, salvando o valor criptografado no arquivo de saída dos dados

for I := 0 to msEntrada.Size - 1 do begin msEntrada.Read(C, 1); C := (C xor not(ord(chave shr I))); msSaida.Write(C,1); end; msSaida.SaveToFile(arqSaida);

E por fim liberamos as duas variáveis MemoryStream da memória

finally msEntrada.Free; msSaida.Free;end;

E, para que seja chamado o arquivo no momento em que seja feita a crip-tografia pegando os dados de um arquivo de texto para outro basta chamar a função com os arquivos de entrada e saída dos dados e a quantidade de caracteres gerados na criptografia.

procedure TForm1.Button1Click(Sender: TObject);begin Encriptar(‘1.txt’, ‘2.txt’, 26);end;

Conclusão

Essa é uma técnica muito utilizada em softwares para aumentar a proteção de dados contra o acesso indevido, e evitar perda ou desencontro de dados de registros, ideal quando utilizados arquivos de textos simples para que não sejam acessados e seus dados facilmente consultados.

Page 29: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 2011 29

Listando todas as url’s visitadas no Internet Explorer

Uma das maneiras mais fáceis de verificar e controlar o acesso a sites é a listagem de todas as URL’s acessadas naquele computador, o que nos possibilita com essa dica fazer com que o Delphi liste todos os links acessados para assim possamos utilizar esta lista para controle de acesso a sites, conteúdo proibido e downloads indevidos, baseados nesta listagem.

Para criarmos esse controle, primeiramente criaremos uma procedure que nesta dica recebe o nome de ListaURL, e seu parâmetro de retorno da listagem sendo do tipo TStrings

procedure TForm1.ListaURL(Urls: TStrings);

Declaramos 3 variaveis, uma do tipo TRegistry, que fará o acesso aos dados de registros do Editor de Registros do Windows, uma do Tipo TStringList, que armazenará a listagem de todas as URLS visitadas, e uma do tipo Integer que irá auxiliar no controle de loops da procedure

var Reg: TRegistry; S: TStringList; i: Integer;

Primeiro inicializamos o Tipo TRegistry com o método create, instanciando e preparando para que possaser utilizada

begin Reg := TRegistry.Create;

Logo acessamos os nós dos Registros do Windows para encontrar o campo TypedURLs, que é a responsável por controlar a listagem de todos os dados de URL do Internet Explorer, fazendo uma verificação se sua chave está aberta.

try Reg.RootKey := HKEY_CURRENT_USER; if Reg.OpenKey(‘Software\Microsoft\Internet Explorer\TypedURLs’, False) then

Caso não tenha nenhum registro, primeiro instanciamos o objeto TStrin-gList com o método create, limpamos o componente ListBox, que irá receber a listagem de URL’s, pegando a listagem com os nomes da urls e inserindo na StringList, e, caso não haja nenhum registro, ele irá dentro do comando de repe-tição FOR, pegar todos os nomes das URL’s acessadas a partir deste momento.

begin S := TStringList.Create; try ListBox1.Clear; reg.GetValueNames(S); for i := 0 to S.Count - 1 do begin Urls.Add(reg.ReadString(S.Strings[i])); end;

Por fim liberamos da memória as variáveis do tipo TStringList e TRegistry

finally S.Free; end; Reg.CloseKey; end; finally Reg.Free; end;end;

Para que seja executada esta função basta chamar no evento OnClick a procedure, informando como parâmetro o objeto onde será listado as URL’s

ListaURL (ListBox1.Items);

Conclusão

Essa é uma função bem simples mais muito utilizada em softwares que fazem a verificação de controle de acesso a websites, sendo de fundamental uti-lização, pois se baseiam nessa listagem permitir ou restringir os seus usuários.

Page 30: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 201130

VerticalHorizontal

Page 31: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 2011

Page 32: The Club - megazine · No artigo: “Streams e compressão de arquivos com ZipMaster em Delphi”, mostro a vocês como Streams e a compressão de arquivos são importantes em aplicações

dezembro 2011