Java Nio

Layouts

Java N.IO Layouts

Praticando

É muito comum em projetos reais sermos solicitados para converter nossos objetos em conteúdo texto para após serem escritos em um arquivo .txt ou .csv, e também o inverso, ler as linhas de um arquivo e converter em um ou uma lista de objetos.

Para ilustrar o uso de layouts para geração de arquivos texto utilizando uma linguagem orientada a objetos como o Java, iremos ampliar o contexto do exemplo citado acima:

O nosso sistema já tem disponível dados de contatos com base numa lista de objetos deverivados da classe Cadastro.java com as características que deverão ser escritas em um arquivo:

public class Cadastro {
    String  nome;
    String  sexo;
    Long    telefone;
    LocalDate dataNascimento;
    Double valorSugerido;
    boolean cliente;

    // este construtor é somente para ilustrar este exemplo
    // evite propagar esta estratégia ao longo dos seus estudos e projetos
    public Contato(String nome, String sexo, Long telefone, LocalDate dataNascimento, Double valorSugerido, boolean cliente) {
        this.nome = nome;
        this.sexo = sexo;
        this.telefone = telefone;
        this.dataNascimento = dataNascimento;
        this.valorSugerido = valorSugerido;
        this.cliente = cliente;
    }
    
    //métodos getters para obter os dados dos objetos
}

Delimitado

Um arquivo com layout delimitado utiliza um delimitador (separador de características) diante de uma linha no arquivo. Este delimitador costuma ser , vírgula, ; ponto e vírgula ou | pipe onde grande maioria dos cenários utilizam o padrão de arquivo .csv.

Vamos iniciar a conversão da nossa lista de objetos para uma lista de strings com colunas delimitadas utilizando ;;

public static void escreverLayoutDelimitado(List<Cadastro> cadastros){
    System.out.println("***** - LAYOUT DELIMITADO - *****");
    
    try {
        StringBuilder conteudo = new StringBuilder();
        
        for (Cadastro cadastro : cadastros) {
            conteudo.append(cadastro.getNome() + ";");
            conteudo.append(cadastro.getSexo() + ";");
            conteudo.append(cadastro.getTelefone() + ";");
            conteudo.append(cadastro.getDataNascimento() + ";");
            conteudo.append(cadastro.getValorSugerido() + ";");
            conteudo.append(cadastro.isCliente());
            conteudo.append(System.lineSeparator());
        }
        System.out.println(conteudo.toString());
        
        Path arquivoDestino = Paths.get("C:\\arquivos\\lista-contatos-modelo-delimitado.csv");
        
        Files.write(arquivoDestino, conteudo.toString().getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE);
    
    }catch (Exception ex){
        ex.printStackTrace();
    }
}
***** - LAYOUT DELIMITADO - *****
Joemia Giron Lyrio Monnerat;F;8321485886;1984-06-30;35.0;false
Reginaldo Folly Barboza Brito;M;2127056726;1990-03-17;40.0;true
Mariza Gadelha Bastida Carneiro;F;9124168455;1889-08-18;40.0;false
Mirian Venancio Portela Ignacia;M;6832598389;1975-11-21;29.0;true
🏆 Sucesso
O conteúdo acima não será mais nenhum mistério para você. 😀

Vamos inverter o nosso cenário? Que tal lermos o arquivo .csve gerar os objetos de cadastro?

public static List<Cadastro>  lerLayoutDelimitado(){
    List<Cadastro> cadastros = new ArrayList<>();
    
    try {
        Path arquivoOrigem = Paths.get("C:\\arquivos\\lista-contatos-modelo-delimitado.csv");
        
        List<String> linhas = Files.readAllLines(arquivoOrigem);
        // imprimindo cada linha obtida no arquivo
        for(String linha:linhas){
            String[] colunas = linha.split("\\;"); // -> quebra uma linha em colunas com base no delimitador;
            String nome = colunas[0];
            String sexo = colunas[1];
            Long telefone = Long.valueOf(colunas[2]);
            LocalDate dataAniversario = LocalDate.parse(colunas[3]);
            Double valorSugerido = Double.valueOf(colunas[4]);
            boolean cliente = Boolean.valueOf(colunas[5]);
            
            //criando um novo cadastro e adicionando na lista de acordo com os valores de cada coluna
            cadastros.add(new Cadastro(nome,sexo,telefone,dataAniversario,valorSugerido,cliente));
        }
    }catch (Exception ex){
        ex.printStackTrace();
    }

    // ao retornar a lista de objetos
    // você poderá realizar qualquer ação com a lista retornada
    
    return cadastros;
}

Posicional

Um arquivo com layout posicional realiza um controle das colunas com base em um estrutura de comprimento (m,n) previamente definida resultando em realizar o particionamento (subtring) dos caracteres em uma linha.

Vamos ilustrar uma simulação de layout posicional que seria aderente ao nosso cenário atual:

NomeTam.Observação
Nome30Preencha com espaço em branco à esquerda ou cortar os caracteres após a posição 30
Sexo1salvar M ou F
Telefone10Somente números
Aniversário10Salvar no formato dd-MM-aaaa
Valor Sugerido7Salvar no formato 0000.00
Cliente1Salvar 1 para true e zero para false
🔔 Atenção
O Layout acima é somente uma ilustração do que você pode se deparar em projetos reais, a proposta aqui é ter um direcionamento inicial de como interagir em requisitos iguais a estes.Recomandamos se desafiar e implementar layouts mais complexos com requisitos mais bem elaborados como no nosso repositório Conta Rural.
public static void escreverLayoutPosicional(List<Cadastro> cadastros) {
    try {
        System.out.println("***** - LAYOUT POSICIONAL - *****");
        
        StringBuilder conteudo = new StringBuilder();
        for (Cadastro cadastro : cadastros) {
            String nome = cadastro.getNome();
            // calma, não será assim para sempre
            if (nome.length() > 30)
            nome = nome.substring(0, 30);
            
            // pesquise sobre String.format
            if (nome.length() < 30)
            nome = String.format("%-30s", nome);
            
            conteudo.append(nome);
            conteudo.append(cadastro.getSexo().toUpperCase());
            conteudo.append(cadastro.getTelefone());
            conteudo.append(cadastro.getDataNascimento());
            
            DecimalFormat decimalFormat = new DecimalFormat("#0000.00");
            
            String valorFormatado = decimalFormat.format(cadastro.getValorSugerido());
            conteudo.append(valorFormatado.replaceAll("\\,", "\\.")); // -> troca , por .
            conteudo.append(cadastro.isCliente() ? "1" : "0");
            
            // nova linha
            conteudo.append(System.lineSeparator());
        }
    
        System.out.println(conteudo.toString());
        
        Path arquivoDestino = Paths.get("C:\\arquivos\\lista-contatos-modelo-posicional.txt");
        
        Files.write(arquivoDestino, conteudo.toString().getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE);
    
    }catch (Exception ex){
        ex.printStackTrace();
    }
}
***** - LAYOUT POSICIONAL - *****
Joemia Giron Lyrio Monnerat   F83214858861984-06-300035.500
Reginaldo Folly Barboza Brito M21270567261990-03-170040.301
Mariza Gadelha Bastida CarneirF91241684551889-08-180040.700
Mirian Venancio Portela IgnaciM68325983891975-11-210029.501

Ler arquivos com layout posicional é muito semelhante ao layout posicional, precisamos obter uma lista de Strings mas desta vez iremos particionar (substring) cada linha de acordo o comprimento correspondente.

public static List<Cadastro>  lerLayoutPosicional(){
    List<Cadastro> cadastros = new ArrayList<>();

    try {
        Path arquivoOrigem = Paths.get("C:\\arquivos\\lista-contatos-modelo-posicional.txt");

        List<String> linhas = Files.readAllLines(arquivoOrigem);
        // imprimindo cada linha obtida no arquivo
        for(String linha:linhas){
            String nome = linha.substring(0,30).trim(); // -> pego os caracteres da posição 0 a 30, trim() remove espaços laterias
            String sexo = linha.substring(30,31); // observe que sempre o primeiro parâmetro tem o valor que o segundo parâmetro anterior
            Long telefone = Long.valueOf(linha.substring(31,41)); // 41-31=10
            LocalDate dataAniversario = LocalDate.parse(linha.substring(41,51));
            Double valorSugerido = Double.valueOf(linha.substring(51,58));
            boolean cliente = linha.substring(58,59).equals("1");

            //criando um novo cadastro e adicionando na lista de acordo com os valores de cada coluna
            cadastros.add(new Cadastro(nome,sexo,telefone,dataAniversario,valorSugerido,cliente));
        }
    }catch (Exception ex){
        ex.printStackTrace();
    }

    // ao retornar a lista de objetos
    // você poderá realizar qualquer ação com a lista retornada

    return cadastros;
}
Se você pretende explorar um pouco mais sobre manipulação de arquivos com foco em compreensão e prática na implementação de desafios reais utilizando Java N-IO, assista nossas lives pelos links abaixo.

Java4Business - Live 01

Java4Business - Live 02

Java4Business - Live 03