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.