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.

Layout arquivo txt

Figura 1 – Layout arquivo txt

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.

Listagem 1. Classe Salario
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 +
                '}';
    }
}
Listagem 2. Classe Usuario
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.

Listagem 3. Classe UsuarioSalario
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().

Listagem 4. Classe Executa – Método 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(List usuarioSalarioList) {

        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.

Listagem 5. Classe Main – arrays
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.

Listagem 6. Classe Main – Método getNome()
/**
 * 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.

Listagem 7. Classe Main – Método getProfissao()
/**
 * 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.

Listagem 8. Classe Main – Método getSalario()
/**
 * 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.

Listagem 9. Classe Main – Método getData()
/**
 * 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.

Listagem 10. Classe Main – Método escreverArquivo()
private static void escreverArquivo() {
	//Cria uma lista do tipo UsuarioSalario
	List usuarioSalarios = 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.

Listagem 11. Classe Executa – Método lerArquivo()
public List lerArquivo() {
	//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().

Listagem 12. Classe Main – Método lerArquivo()
private static void lerArquivo() {
	Executa executa = new Executa();
	// recebe os valores lidos no arquivo
	// e os insere em uma lista
	List usuarioSalarios = 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.

Ballem

Marcio Ballem é bacharel em Sistemas de Informação pelo Centro Universitário Franciscano em Santa Maria/RS. Tem experiência com desenvolvimento Delphi e Java em projetos para gestão pública e acadêmica. Possui certificação em Java, OCJP 6.

Você pode gostar...