Java – Leer archivo Excel

Leer una hoja de cálculo es fácil hasta que te das cuenta de dos cosas: en Excel todo número es un decimal y las celdas vacías no existen. Las dos tienen solución, pero hay que conocerlas.

La dependencia

<dependency>
  <groupId>org.apache.poi</groupId>
  <artifactId>poi-ooxml</artifactId>
  <version>5.5.1</version>
</dependency>

Recorrer la hoja

import org.apache.poi.ss.usermodel.*;
import java.io.File;
import java.time.format.DateTimeFormatter;

public class LeerExcel {
    public static void main(String[] args) throws Exception {
        var f = DateTimeFormatter.ofPattern("dd/MM/yyyy");

        try (Workbook libro = WorkbookFactory.create(new File("ventas.xlsx"))) {
            Sheet hoja = libro.getSheetAt(0);
            System.out.println("hoja \"" + hoja.getSheetName()
                             + "\", última fila: " + hoja.getLastRowNum());

            FormulaEvaluator ev = libro.getCreationHelper().createFormulaEvaluator();

            for (Row fila : hoja) {
                var sb = new StringBuilder();
                for (Cell cel : fila) sb.append(valor(cel, ev, f)).append(" | ");
                System.out.println("  " + sb);
            }
        }
    }

    static String valor(Cell c, FormulaEvaluator ev, DateTimeFormatter f) {
        return switch (c.getCellType()) {
            case STRING  -> c.getStringCellValue();
            case BOOLEAN -> String.valueOf(c.getBooleanCellValue());
            case NUMERIC -> DateUtil.isCellDateFormatted(c)
                    ? c.getLocalDateTimeCellValue().toLocalDate().format(f)
                    : String.valueOf(c.getNumericCellValue());
            case FORMULA -> c.getCellFormula() + " = " + ev.evaluate(c).getNumberValue();
            case BLANK   -> "";
            default      -> "?";
        };
    }
}
salidahoja "Ventas", última fila: 4
  Producto | Unidades | Precio | Importe | Fecha | 
  Camiseta | 12.0 | 25.0 | B2*C2 = 300.0 | 01/10/2026 | 
  Bufanda | 3.0 | 9.0 | B3*C3 = 27.0 | 02/10/2026 | 
  Mochila | 1.0 | 34.0 | B4*C4 = 34.0 | 03/10/2026 | 
  Total | SUM(D2:D4) = 361.0 |

Los cuatro detalles que importan

1. WorkbookFactory.create adivina el formato. Devuelve un XSSFWorkbook o un HSSFWorkbook según lo que encuentre, así que el mismo código lee .xlsx y .xls.

2. Todo número es un double. Fíjate en el 12.0: en la hoja escribimos un entero, pero en Excel no hay enteros. Para recuperarlo hay que convertir, y conviene hacerlo con cuidado si el número es grande: (int) celda.getNumericCellValue().

3. Una fecha es un número con formato. No hay tipo de fecha: por eso DateUtil.isCellDateFormatted, que mira el formato de la celda para decidir. Si alguien le quita el formato en Excel, tu programa lee un 46296.

4. Una fórmula no trae su resultado a menos que lo pidas. El FormulaEvaluator la calcula; getCellFormula() devuelve el texto. También puedes leer el último valor que Excel guardó con celda.getNumericCellValue() sobre una celda de fórmula.

Y la trampa gorda: mira la última fila de la salida. La fila del total tiene «Total» en la columna A y la suma en la D, pero solo han salido dos valores, sin hueco en medio. Es porque for (Cell cel : fila) se salta las celdas que nunca se crearon, de modo que las columnas dejan de coincidir. Si necesitas las posiciones, recorre por índice:
for (int c = 0; c < fila.getLastCellNum(); c++) {
    Cell cel = fila.getCell(c, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
    // aquí c siempre es la columna real
}

Lo mismo pasa con las filas: hoja.getLastRowNum() cuenta hasta la última con datos, pero hoja.getRow(i) puede devolver null para una fila intermedia vacía.

Dos avisos que vas a ver en la consola. POI arrastra Log4j como interfaz y, si no hay ninguna implementación en el proyecto, imprime ERROR Log4j API could not find a logging provider y sigue funcionando. Se quita añadiendo log4j-core o log4j-to-slf4j. Y poi-ooxml arrastra unas cuantas dependencias —xmlbeans, commons-compress, commons-collections4—: con Maven vienen solas, pero si compilas a mano hay que bajarlas todas.
Si el archivo es muy grande y solo vas a leerlo una vez, existe el modo evento de POI (XSSF con SAX), que recorre el XML interno sin cargar la hoja en memoria. Es bastante más código, pero es la única forma de leer un libro de 200 MB.

Más información en inglés: Read Excel file with Apache POI.

Todo el código se compiló y se ejecutó con Java 25 LTS en un contenedor limpio antes de publicar esta página; las salidas están copiadas de esa ejecución.

1 comentario en «Java – Leer archivo Excel»

Deja un comentario