O Apache POI é uma biblioteca amplamente utilizada para manipular arquivos do Microsoft Excel em ambientes Java. Este artigo aborda os principais desafios enfrentados durante a leitura de arquivos .xls (Excel 2003) e .xlsx (Excel 2007+), além de soluções práticas para erros frequentes.
1. Diferenças entre .xls e .xlsx
Os formatos .xls e .xlsx são incompatíveis em nível estrutural. O primeiro é baseado em binários antigos, enquanto o segundo utiliza XML dentro de um arquivo ZIP. Para lidar com ambos, recomenda-se o uso da classe WorkbookFactory, que detecta automaticamente o tipo de arquivo:
Workbook workbook = WorkbookFactory.create(new File("caminho/arquivo.xlsx"));
Essa abordagem elimina a necessidade de escolher manualmente entre HSSFWorkbook (para .xls) ou XSSFWorkbook (para .xlsx).
No entanto, o uso do formato .xlsx exige a inclusão da dependência xmlbeans, pois o Apache POI não inclui essa biblioteca por padrão. A ausência de xmlbeans.jar resulta em erros como:
java.lang.NoClassDefFoundError: org/apache/xmlbeans/XmlObject
Certifique-se de adicionar a dependência correta no projeto (Maven ou Gradle).
2. Problema de Registro Inválido: Unexpected record type
Durante a leitura de alguns arquivos, pode ocorrer uma exceção como:
java.lang.RuntimeException: Unexpected record type (org.apache.poi.hssf.record.DefaultRowHeightRecord)
Esse erro geralmente está relacionado a arquivos corrompidos ou criados com versões não padronizadas do Excel. A solução mais simples é abrir o arquivo no Excel, salvar novamente e tentar novamente.
3. Processamento em Lote: Leitura de Todos os Aruqivos Excel em uma Pasta
A seguir, um exemplo funcional que percorre todos os arquivos Excel em um diretório, lê suas planilhas e salva os dados em um arquivo de texto:
import org.apache.poi.ss.usermodel.*;
import java.io.*;
import java.util.Arrays;
public class LeitorExcelLote {
public static void main(String[] args) {
String caminhoPasta = "C:\\Users\\Usuario\\Documentos\\Planilhas";
File pasta = new File(caminhoPasta);
File[] arquivos = pasta.listFiles((dir, nome) ->
nome.toLowerCase().endsWith(".xls") || nome.toLowerCase().endsWith(".xlsx")
);
if (arquivos == null || arquivos.length == 0) {
System.out.println("Nenhum arquivo Excel encontrado.");
return;
}
System.out.println("Total de arquivos Excel: " + arquivos.length);
for (File arquivo : arquivos) {
processarArquivo(arquivo.getAbsolutePath());
}
}
private static void processarArquivo(String caminho) {
try (Workbook workbook = WorkbookFactory.create(new File(caminho))) {
Sheet planilha = workbook.getSheetAt(0);
for (Row linha : planilha) {
StringBuilder linhaTexto = new StringBuilder();
for (Cell celula : linha) {
linhaTexto.append(obterValorCelula(celula)).append("---");
}
salvarEmArquivo(linhaTexto.toString());
System.out.println(linhaTexto);
}
} catch (Exception e) {
System.err.println("Erro ao processar " + caminho + ": " + e.getMessage());
}
}
private static Object obterValorCelula(Cell celula) {
switch (celula.getCellType()) {
case BLANK: return null;
case BOOLEAN: return celula.getBooleanCellValue();
case ERROR: return celula.getErrorCellValue();
case FORMULA: return celula.getCellFormula();
case NUMERIC: return celula.getNumericCellValue();
case STRING: return celula.getStringCellValue();
default: return null;
}
}
private static void salvarEmArquivo(String conteudo) {
File arquivo = new File("resultados.txt");
if (!arquivo.exists()) {
try {
arquivo.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
try (FileWriter escritor = new FileWriter(arquivo, true);
PrintWriter saida = new PrintWriter(escritor)) {
saida.println(conteudo);
saida.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Este código garante tratamento adequado de exceções, uso seguro de recursos com try-with-resources, e evita vazamentos de memória. Além disso, o método obterValorCelula foi simplificado e centralizado para melhor legibilidade.