Implementação de um Conversor de CSV para Arquivos de Largura Fixa em Java

No ecossistema de processamento de dados e integração de sistemas, o formato CSV (Comma-Separated Values) é amplamente utilizado devido à sua simplicidade. Contudo, sistemas legados ou processos bancários muitas vezes exigem arquivos de largura fixa (fixed-width), onde cada campo possui uma posição e tamanho predefinidos. Este artigo descreve a arquitetura e implementação de uma ferramenta robusta para realizar essa transição utilizando Java.

Fundaemntos da Conversão de Formatos

A transição de um formato delimitado para um formato posicional exige precisão no tratamento de strings. Enquanto o CSV separa informações por vírgulas ou pontos e vírgulas, o formato de largura fixa depende de preenchimentos (padding) com espaços ou zeros para garantir que cada coluna ocupe exatamente o espaço reservado no layout do arquivo.

Leitura e Manipulação de Arquivos com Java NIO

Para um processamento eficiente, utilizamos as APIs modernas do Java, como o pacote java.nio.file. A leitura linha a linha é perferível para evitar o consumo excessivo de memória em arquivos extensos.

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.IOException;

public class GerenciadorArquivos {
    public void transformarArquivo(String pathOrigem, String pathDestino) {
        Path entrada = Paths.get(pathOrigem);
        Path saida = Paths.get(pathDestino);

        try (BufferedReader leitor = Files.newBufferedReader(entrada);
             BufferedWriter escritor = Files.newBufferedWriter(saida)) {
            
            String registro;
            while ((registro = leitor.readLine()) != null) {
                String[] colunas = registro.split(",");
                String linhaFormatada = processarCampos(colunas);
                escritor.write(linhaFormatada);
                escritor.newLine();
            }
        } catch (IOException e) {
            System.err.println("Erro na operação de I/O: " + e.getMessage());
        }
    }

    private String processarCampos(String[] campos) {
        // Lógica de formatação será implementada aqui
        return String.join("", campos);
    }
}

Processamento de Strings e Alinhamento

A alma do conversor reside na capacidade de ajustar o tamanho das strings. Se um dado é menor que o limite da coluna, ele deve ser preenchido; se for maior, deve ser truncado para evitar que invada o campo adjacente.

public class FormatadorTexto {
    public static String ajustarTamanho(String texto, int largura, char preenchimento) {
        if (texto == null) texto = "";
        
        if (texto.length() >= largura) {
            return texto.substring(0, largura);
        }
        
        StringBuilder sb = new StringBuilder(texto);
        while (sb.length() < largura) {
            sb.append(preenchimento);
        }
        return sb.toString();
    }
}

Construção da Linha de Saída

Ao definir as regras de negócio, associamos cada índice do CSV a uma largura específica no arquivo de destino. O exemplo abaixo demonstra como construir um registro baseado em um layout predefinido.

public class MotorConversao {
    public String criarRegistroPosicional(String[] dados) {
        int[] mapaLarguras = {10, 30, 15}; // Ex: ID (10), Nome (30), Valor (15)
        StringBuilder registroFinal = new StringBuilder();

        for (int i = 0; i < mapaLarguras.length; i++) {
            String valorOriginal = (i < dados.length) ? dados[i] : "";
            registroFinal.append(FormatadorTexto.ajustarTamanho(valorOriginal, mapaLarguras[i], ' '));
        }
        
        return registroFinal.toString();
    }
}

Gerenciamento de Erros e Validação de Dados

Um conversor resiliente deve validar a integridade dos dados antes da transformação. Isso inclui verificar se o número de colunas do CSV é consistente e se existem caracteres especiais que podem corromper a saída posicional.

public class ValidadorDados {
    public static boolean verificarIntegridade(String[] campos, int esperado) {
        if (campos == null || campos.length != esperado) {
            // Log de erro ou lançamento de exception customizada
            return false;
        }
        return true;
    }
}

Alta Performance com Multithreading

Para processar gigabytes de dados, a execução sequencial torna-se um gargalo. Podemos dividir o arquivo em segmentos ou processar lotes de linhas em paralelo utilizando um ExecutorService.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ProcessadorParalelo {
    private final ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    public void agendarTarefa(Runnable tarefa) {
        executor.execute(tarefa);
    }

    public void finalizar() {
        executor.shutdown();
    }
}

Interface e Integração

A ferramenta pode ser exposta via CLI (Command Line Interface) para automação em servidores Linux ou através de uma GUI (Graphical User Interface) para usuários finais. A integração em pipelines de CI/CD ou fluxos de ETL (Extract, Transform, Load) é simplificada através da modularização das classes de processamento, permitindo que o conversor seja instanciado como uma biblioteca dentro de outros sistemas Java.

Tags: java csv-parser file-io Multithreading software-engineering

Publicado em 6-15 03:45 por Thomas