Manipulando arquivo Txt com JFileHelpers
Nos dias atuais ainda é necessário muitas vezes a manipulação de arquivos do tipo texto (.txt). Embora cada vez mais se use arquivos do tipo XML, o TXT é utilizado principalmente como mecanismo de exportação e importação de dados. Uma biblioteca muito boa para este fim é a JFileHelpers, um mecanismo para os programadores diminuírem o esforço em desenvolver projetos em que se faz necessária a manipulação de arquivos do tipo TXT baseados em layout.
1. JFileHelpers
O JFileHelpers é uma biblioteca construída para automatizar as tarefas de manipulação de arquivos do tipo texto. Geralmente um arquivo texto que tem como objetivo a exportação de dados é baseado em uma estrutura definida, chamada de layout. O JFileHelpers facilita o trabalho do programador porque possibilita definir através de anotações a estrutura do arquivo.
O tamanho do texto, a formatação de uma data, o alinhamento do texto para esquerda, direita, entre outras funções, todas baseadas em anotações. O download da biblioteca pode ser feito através do link: http://tinyurl.com/3spjwjv.
2. Estrutura de um arquivo
Vamos partir para os exemplos. Primeiro vamos criar uma estrutura (layout) para o arquivo que conterá dados de duas classes Usuário e Salário. A estrutura pode ser visualizada na Figura 1.
O layout está definida como mostrado na linha 1 da Figura 1. Veja que existem oito (8) divisões e cada uma delas possui um tamanho especifico.
- A 1ª divisão tem um tamanho definido para até 5 caracteres e conterá um código.
- A 2ª divisão tem um tamanho definido para até 30 caracteres e conterá o nome do usuário.
- A 3ª divisão tem um tamanho definido para até 08 caracteres e conterá uma data.
- A 4ª divisão tem um tamanho definido para até 20 caracteres e conterá o nome de uma profissão.
- A 5ª divisão terá um tamanho definido para até 10 caracteres e conterá o valor de um salário.
- A 6ª divisão terá um tamanho definido para até 10 caracteres e conterá o valor de uma comissão sobre o salário.
- A 7ª divisão terá um tamanho definido para até 10 caracteres e conterá o valor de um desconto sobre o salário.
- A 8ª divisão terá um tamanho definido para até 10 caracteres e conterá o valor de uma remuneração, que será o valor do salário (+) a comissão (–) o valor do desconto.
3. Classes iniciais do projeto
Agora que temos uma estrutura definida para o arquivo, vamos começar a desenvolver o projeto. Primeiro não se esqueça de baixar a biblioteca JFileHelpers e adicioná-la em seu projeto.
Vamos criar a classe que conterá os dados dos salários dos usuários, veja na Listagem 1.
package com.wp.mb.tutorialJFH; public class Salario { private Double salario; private Double comissao; private Double desconto; private Double remuneracao; public Double getRemuneracao() { return remuneracao; } public void setRemuneracao(Double salario, Double comissao, Double desconto) { this.remuneracao = salario + comissao - desconto; } // gere os demais métodos getters and setters @Override public String toString() { return "Salario{" + "salario=" + salario + ", comissao=" + comissao + ", desconto=" + desconto + ", remuneracao=" + remuneracao + '}'; } }
package com.wp.mb.tutorialJFH; import java.util.Date; public class Usuario { private Integer codigo; private String nome; private Date dtNascimento; private String profissao; private Salario salario; // gere os metodos getters and setters @Override public String toString() { return "Usuario{" + "codigo=" + codigo + ", nome='" + nome + '\'' + ", dtNascimento=" + dtNascimento + ", profissao='" + profissao + '\'' + ", salario=" + salario + '}'; } }
Agora iremos criar a uma classe chamada UsuarioSalario
que conterá as anotações referentes a estrutura do arquivo. Veja na Listagem 3 as anotações utilizadas e preste atenção aos comentários descritos no código para entender para que serve cada anotação.
package com.wp.mb.tutorialJFH; import org.coury.jfilehelpers.annotations.*; import org.coury.jfilehelpers.enums.AlignMode; import org.coury.jfilehelpers.enums.ConverterKind; import org.coury.jfilehelpers.enums.TrimMode; import java.util.Date; public class UsuarioSalario { //Define o n° de caracteres do campo @FieldFixedLength(5) //Define o alinhamento do campo e o caracter que deve ser // usado quando sobrar espaço em branco dentro das posições @FieldAlign(alignMode = AlignMode.Right, alignChar = '0') private Integer codigo; @FieldFixedLength(30) @FieldAlign(alignMode = AlignMode.Left, alignChar = ' ') private String nome; @FieldAlign(alignMode = AlignMode.Left, alignChar = '0') @FieldFixedLength(8) //Define o formato em que a data deve ser salva no arquivo @FieldConverter(converter = ConverterKind.Date, format = "ddMMyyyy") private Date dtNascimento; @FieldFixedLength(20) @FieldAlign(alignMode = AlignMode.Left, alignChar = ' ') private String profissao; @FieldFixedLength(10) @FieldAlign(alignMode = AlignMode.Right, alignChar = '0') private double salario; @FieldFixedLength(10) @FieldAlign(alignMode = AlignMode.Right, alignChar = '0') private double comissao; @FieldAlign(alignMode = AlignMode.Right, alignChar = '0') @FieldFixedLength(10) private double desconto; @FieldFixedLength(10) @FieldAlign(alignMode = AlignMode.Right, alignChar = '0') private double remuneracao; // gere os métodos getters and setters }
Explicando melhor a anotação @FieldAlign
: Através desta anotação é possivel definir se os caracteres serão alinhados para esquerda, direita ou no centro do campo. Um campo de tamanho 20 e que tenha um nome que utilize 10 caracteres, tera 10 espaços vazios. Através desta anotação você pode definir o alinhamento, como também o que será utilizado no espaço que ficou vazio. Veja que para o campo nome
foi utilizado o vazio, ou espaço em branco, já para os campos numéricos foi utilizado o número zero (0) . Por exemplo, se no campo codigo
que tem tamanho de 5 caracteres tiver um número com 4 caracteres [1234] a posição restante será definida como zero. Neste caso o alinhamento está a direita, então o zero será preenchido ao lado esquerdo [01234].
Outra anotação interessante e que não foi utilizado no exemplo é a @FieldOptional
. Quando você tem um campo definido no arquivo, mas o valor no momento de gerar o arquivo for nulo, será necessário setar esta anotação no atributo da classe para evitar uma exceção. Utilize essa anotação para campos que possam não ter dados em alguma linha do arquivo.
Para gerar o arquivo vamos criar um método específico, ele fará parte da classe Executa
conforme a Listagem 4. O método escreverArquivo()
terá como par metro uma lista (java.util.List
) contendo os dados que serão salvos no arquivo. Para gravar o arquivo é muito simples, basta criar um objeto do tipo FileHelperEngine
indicando qual classe contém as anotações. Depois então, utilizasse o método writeFile()
do objeto criado. Neste método passamos 2 parametros, o 1° é o nome e diretório onde o arquivo será salvo e o segundo é a lista recebida por par metro do metodo escreverArquivo()
.
package com.wp.mb.tutorialJFH; import org.coury.jfilehelpers.engines.FileHelperEngine; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class Executa { public void escreverArquivo(ListusuarioSalarioList) { FileHelperEngine engineUser = new FileHelperEngine (UsuarioSalario.class); try { engineUser.writeFile("C:\\UsuarioSalario.txt", usuarioSalarioList); System.out.println("\n*** Arquivo gerado com Sucesso! ***\n"); } catch (IOException e) { System.out.println("\n *** Ocorreu uma falha na " + "geracao do Arquivo ***\n"); e.printStackTrace(); } } }
4. Criando a classe Main
Agora vamos criar a classe Main
. Dentro desta classe foram criados alguns métodos para gerar os dados que serão inseridos no arquivo. Os dados serão gerados de forma randômica. Na Listagem 5 temos três arrays que contém os dados referentes ao Nome (FIRST_NAME
) (LAST_NAME
) e Profissão (JOB
) de cada usuário.
package com.wp.mb.tutorialJFH; import java.util.ArrayList; import java.util.Date; import java.util.List; public class Main { private static final String[] FIRST_NAME = { "Marcio", "Vanessa", "Marina", "Daniel", "Alice", "Bruno", "Olivia","Tatiane", "Carla", "Carlos", "Daniel", "Fabiane", "Fabiano", "Rita de Cassia", "Aline", "Marcos Daniel", "Leonardo", "Sandra", "Maria Luiza", "Victor", "Anete", "Isabel", "Mario", "Nelson", "Mario Nelson", "Marta Anita", "Lindsei", "Paulo", "Osmar", "Ricardo", "Rodrigo", "Itamar", "Fernanda" }; private static final String[] LAST_NAME = { "Da Silva", "Pereira", "de Souza", "Gomes Lima", "de Fortes Matos", "da Fonseca", "da Rocha Lima", "de Sousa Marros", "Londero Gils", "Visconde", "Silva e Lima", "Mattos Perez", "Figueira", "Nunes Vasques", "do Porto", "Ferreira", "Gonçalves", "Rigo Loes", "da Costa", "da Vinculle", "Ballivare", "de Maranhão", "da Assunção", "Pires Vasques", "Secco", "Oliveira Saccol" }; private static final String[] JOB = { "Arquiteto(a)", "Contador(a)", "Marceneiro(a)", "Estoquista", "Administrador(a)", "Programador(a)", "Analista de Sistemas", "Professor(a)", "Motorista", "Geologo(a)", "Matematico(a)", "Médico(a)", "Manobrista", "Piloto", "Faxineiro(a)", "Telefonista", "Enfermeiro(a)", "Bombeiro", "Policial", "Vendedor(a)", "Tesoreiro(a)", "Mestre de Obras", "Biologo(a)", "Diarista", "Jornalista" }; }
Vamos usar o método getNome()
da Listagem 6 para gerar os nomes com sobre nome de cada um dos usuários.
/** * Sorteia um nome e um sobre nome usando o método rondomico da classe Math * @return String : nome + sobrenome */ private static String getNome() { int first = (int) (Math.random() * FIRST_NAME.length); int last = (int) (Math.random() * LAST_NAME.length); //System.out.println("first: " + first); //System.out.println("last: " + last); return FIRST_NAME[first] + " " + LAST_NAME[last]; }
O método getProfissao()
da Listagem 7 será responsável por gerar a profissão de cada um dos usuários.
/** * Sortei uma profissão usando o método rondomico da classe Math * @return String - profissao */ private static String getProfissao() { int job = (int) (Math.random() * JOB.length); //System.out.println("job: " + job); return JOB[job]; }
O método getSalario()
da Listagem 8 será responsável por gerar os valores referentes a salário, comissão e descontos de cada usuário.
/** * Gera os itens do salario de maneira randomica * @return Double[] - 0 salario, 1 comissao, 2 desconto */ private static Double[] getSalario() { Double salario = 600.00 + (Math.random() * 2500.00); Double comissao = Math.random() * 500.00; Double desconto = Math.random() * 350.00; //System.out.println("salario: " + salario); //System.out.println("comissao: " + comissao); //System.out.println("desconto: " + desconto); return new Double[]{salario, comissao, desconto}; }
O método getData()
da Listagem 9 será responsável por gerar as datas entre os anos de 1960 e 1995 para cada usuário.
/** * Gera a data de forma randomica * @return String - 0 dia, 1 mês, 2 ano */ private static String getData() { // gera um número aleatório entre 1 e 27 int dia = 1 + (int) (Math.random() * 27); // gera um número aleatório entre 1 e 12 int mes = 1 + (int) (Math.random() * 12); // gera um número aleatório entre 1960 e 1995 int ano = 1960 + (int) (Math.random() * 35); //System.out.println("data: " + dia + "/" + mes + "/" + ano); return dia + "/" + mes + "/" + ano; }
Agora na Listagem 10 vamos criar o método escreverArquivo()
. Este método será responsável por gerar uma lista de usuários e fazer uma chamada ao método escreverArquivo()
da classe Executa
, passando como par metro a lista gerada.
private static void escreverArquivo() { //Cria uma lista do tipo UsuarioSalario ListusuarioSalarios = new ArrayList (); //Loop para criar 100 Usuarios com seus salarios for (int i = 0; i < 100; i++) { //Recebe um valor aleatório para inserir no objeto Salario Double[] valor = getSalario(); Salario s1 = new Salario(); s1.setSalario(valor[0]); //Posicao 0 salario s1.setComissao(valor[1]); //Posicao 1 comissao s1.setDesconto(valor[2]); //Posicao 2 desconto //Pelo método set é gerado o valor da remuneracao s1.setRemuneracao( s1.getSalario(), s1.getComissao(), s1.getDesconto() ); //Vamos gerar um vamor aleatório para o campo codigo int newCodigo = ((int) ((Math.random() * 900) * 100)) + ( 777 + (int) ((Math.random() * 150) * 15)); Usuario u1 = new Usuario(); //usa o método getNome() para inserir um nome u1.setNome(getNome()); //insere o valor aleatório gerado em newCodigo u1.setCodigo(newCodigo); //insere a data através do método randomico getData() u1.setDtNascimento(new Date(getData())); //insere a profissão através do método randomico getProfissao() u1.setProfissao(getProfissao()); u1.setSalario(s1); //Cria um objeto UsuarioSalario com os dados de Usuario e Salario UsuarioSalario us = new UsuarioSalario(); us.setCodigo(u1.getCodigo()); us.setNome(u1.getNome()); us.setDtNascimento(u1.getDtNascimento()); us.setProfissao(u1.getProfissao()); us.setSalario(u1.getSalario().getSalario()); us.setComissao(u1.getSalario().getComissao()); us.setDesconto(u1.getSalario().getDesconto()); us.setRemuneracao(u1.getSalario().getRemuneracao()); //adiciona na lista o objeto gerado usuarioSalarios.add(us); } //após o loop terminar envia a lista para a classe Executa new Executa().escreverArquivo(usuarioSalarios); } public static void main(String[] args) { escreverArquivo(); }
Execute o programa e veja a geração do seu arquivo no diretório indicado na classe Executa
.
5. métodos para Leitura dos Dados Gravados no Txt
Agora que o arquivo foi gerado vamos criar um método para ler os dados inseridos no arquivo. Para isso vamos primeiro criar um método na classe Executa
chamado lerArquivo()
, conforme a Listagem 11.
public ListlerArquivo() { //Cria um objeto FileHelperEngine do tipo UsuarioSalario FileHelperEngine engine = new ArrayList (); //Cria uma lista do tipo UsuarioSalario // para receber os dados do arquivo List usuarioSalarios = new ArrayList (); try { //o método readFile lê o arquivo e preenche a lista //no parametro passamos o local e o nome do arquivo usuarioSalarios = engine.readFile("C:\\UsuarioSalario.txt"); System.out.println("\n*** Arquivo lido com Sucesso! ***\n"); } catch (IOException e) { System.out.println("\n *** Ocorreu uma falha na " + "leitura do Arquivo ***\n"); e.printStackTrace(); } //retorna a lista com os dados obtidos return usuarioSalarios; }
Na classe Main
vamos criar um método para exibir o resultado da leitura do arquivo texto. Para isso, veja na Listagem 12 o método lerArquivo()
.
private static void lerArquivo() { Executa executa = new Executa(); // recebe os valores lidos no arquivo // e os insere em uma lista ListusuarioSalarios = executa.lerArquivo(); // cria uma lista para armazenar os usuarios List usuarios = new ArrayList (); Salario salario = null; Usuario usuario = null; // faz um loop na lista usuarioSalarios e // adiciona na lista usuarios cada usuario do arquivo for (UsuarioSalario us : usuarioSalarios) { salario = new Salario(); salario.setSalario(us.getSalario()); salario.setComissao(us.getComissao()); salario.setDesconto(us.getDesconto()); salario.setRemuneracao(us.getRemuneracao(), 0.0, 0.0); usuario = new Usuario(); usuario.setSalario(salario); usuario.setNome(us.getNome()); usuario.setCodigo(us.getCodigo()); usuario.setDtNascimento(us.getDtNascimento()); usuario.setProfissao(us.getProfissao()); System.out.println(usuario.toString()); } } public static void main(String[] args) { lerArquivo(); }
Conclusão
A biblioteca JFileHelpers se mostra uma ferramenta de apoio muito útil para a manipulação de arquivo texto baseado em layout. é uma forma simples e prática para recuperar informações de um banco de dados e gerar um arquivo através delas. Você pode ler e aprender mais sobre essa biblioteca na página oficial do JFileHelpers: http://jfilehelpers.com.