El proyecto POI (de la Apache Software Foundation) consiste en APIs de Java para manipular ficheros basados en el formato de Documento Compuesto OLE 2 de Microsoft. Desde nuestras aplicaciones Java podemos leer y escribir ficheros MS Excel. Tal vez cuando este leyendo esto podrá leer y escribir ficheros Word. Nosotros nos vamos a centrar en el manejo de archivos Excel.
Dentro del proyecto POI la librería para el manejo de archivos Excel es HSSF. Enlace a POI. También puedes acceder a las páginas de HSSF con ejemplos de código sobre el uso del API. Advertencia: en el momento de escribir está página pude observar que algunos ejemplos de código no estaban actualizados respecto a la última versión de POI-HSSF. En concreto algunos métodos utilizados estaban caducados (deprecated). Pero en general es una introducción clara y sencilla.
Lo primero es la descarga de la librería HSSF, con su correspondiente Javadoc. A continuación se presenta una sencilla aplicación Java stand-alone, el típico programa con su clásico main():
Lo hemos montado en Eclipse y tenemos los siguientes directorios:
El archivo Inicio.java es de una sencillez que no merece comentarios:
package ejemplo01;
public class Inicio {
public static void main( String[] args) {
new GestorHojas();
}
}
El GestorHojas contiene cuatro elemplos. A cada método (ejemplo) le pasamos el archivo xls con el que va a trabajar:
public class GestorHojas {
public GestorHojas() {
paso01("hojas/paso01.xls");
paso02("hojas/paso02.xls");
paso03("hojas/paso03.xls");
paso04("hojas/paso03.xls");
}
...
El primer ejemplo crea un archivo xls que contiene dos hojas vacias. El segundo crea un xls que tiene una cadena de caracteres con una fuente definida en la aplicación. El tercero resulta bastante completo, contiene textos, números, fechas y fórmulas, además de fuentes y colores. El cuarto ejemplo se centra en la lectura y modificación del archivo del ejemplo anterior: lee una celda con un valor numérico, lo duplica y guarda la modificación.
Conceptos importantes:
HSSFSheet hoja1 = wb.createSheet("Hoja A");
HSSFRow fila = hoja1.createRow((short)0);
HSSFCell celda = fila.createCell((short)0);
En resumen, la relación documento-hoja-fila-celda configura una jerarquía.
Otro aspecto importante son los estilos, clase HSSFCellStyle. Por regla general, cuando se quiere introducir en una celda una fuente, color o formato lo que se hace es crear un estilo con las características deseadas (color, etc) y después asignar el estilo a la celda por medio del método setCellStyle(estilo). Por ejemplo para asignar una fuente (wb es un objeto de la clase HSSFWorkbook):
HSSFCellStyle estilo = wb.createCellStyle(); estilo.setFont( fuente ); celda.setCellStyle( estilo );
En este ejemplo el objeto estiloFecha se asigna a una celda que tendrá formato de Fechas:
HSSFCell celdaFecha = fila.createCell((short) 3);
celdaFecha.setCellValue(new Date());
HSSFCellStyle estiloFecha = wb.createCellStyle();
estiloFecha.setDataFormat(HSSFDataFormat.getBuiltinFormat("d-mmm-yy"));
celdaFecha.setCellStyle( estiloFecha );
Formatos:
El código completo de GestorHojas.java:
package ejemplo01;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import java.io.*;
import java.util.*;
public class GestorHojas {
public GestorHojas() {
paso01("hojas/paso01.xls");
paso02("hojas/paso02.xls");
paso03("hojas/paso03.xls");
paso04("hojas/paso03.xls");
}
/*********************************************************************************
Empezamos por algo sencillo:
1 Creamos el libro de trabajo (HSSFWorkbook)
2 Creamos el archivo xls que contendrá el libro
3 Creamos las hojas
4 Guarda (write) el libro en el archivo xls
*********************************************************************************/
public void paso01( String nomArchivo ) {
try {
HSSFWorkbook wb = new HSSFWorkbook();
FileOutputStream archivoSalida = new FileOutputStream( nomArchivo );
HSSFSheet hoja1 = wb.createSheet("Hoja 1");
HSSFSheet hoja2 = wb.createSheet("Hoja 2");
wb.write(archivoSalida);
archivoSalida.close();
System.out.println( "Acaba de crear el archivo xls vacio " + nomArchivo );
}
catch (java.io.FileNotFoundException e) {
System.out.println( "No se se puede acceder al archivo " + e.getMessage());
}
catch (Exception e) {
e.printStackTrace();
}
}
/*********************************************************************************
Creo una celda con un texto. Además uso FUENTE
1 Creamos el libro de trabajo (HSSFWorkbook)
2 Creamos el archivo xls que contendrá el libro
3 Creamos la hoja con una fila y celda
4 Creamos un estilo (crearEstilo()) para indicar una fuente. Ponemos el
estilo en la celda
5 Guarda (write) el libro en el archivo xls
*********************************************************************************/
public void paso02( String nomArchivo ) {
try {
HSSFWorkbook wb = new HSSFWorkbook();
FileOutputStream archivoSalida = new FileOutputStream( nomArchivo );
HSSFSheet hoja1 = wb.createSheet("Hoja 1");
// Crea la primera fila para el título. Empiezan en cero
HSSFRow fila = hoja1.createRow((short)0);
// Crea la celda del título
HSSFCell celda = fila.createCell((short)0);
// Pone a la celda el texto y el estilo
celda.setCellValue( new HSSFRichTextString("Gastos del proyecto") );
celda.setCellStyle( crearEstilo( wb, "Tahoma", (short)14, true ));
// Escribir y cerrar libro
wb.write(archivoSalida);
archivoSalida.close();
System.out.println( "Acaba de crear el archivo " + nomArchivo + " con un título");
}
catch (java.io.FileNotFoundException e) {
System.out.println( "No se se puede acceder al archivo " + e.getMessage());
}
catch (Exception e) {
e.printStackTrace();
}
}
/************************************************************************************
* Crea una fuente y la inserta en un estilo. Devuelve el estilo
************************************************************************************/
public HSSFCellStyle crearEstilo(HSSFWorkbook wb, String nomFuente, short tamanoFuente,
boolean esNegrita) {
HSSFFont fuente = wb.createFont();
fuente.setFontHeightInPoints( tamanoFuente );
fuente.setFontName( nomFuente );
// fuente.setItalic(true);
// fuente.setStrikeout(true);
if ( esNegrita )
fuente.setBoldweight(fuente.BOLDWEIGHT_NORMAL);
// Las fuentes se insertan en un estilo
HSSFCellStyle estilo = wb.createCellStyle();
estilo.setFont( fuente );
return estilo;
}
/*********************************************************************************
Aspectos nuevos:
- Maneja fechas formateadas
- Números alineados a la derecha
- Usa color de fondo
- Formato de %
- FORMULA (Importe * %)
*********************************************************************************/
public void paso03( String nomArchivo ) {
try {
HSSFWorkbook wb = new HSSFWorkbook();
FileOutputStream archivoSalida = new FileOutputStream( nomArchivo );
HSSFSheet hoja1 = wb.createSheet("Hoja A");
////////////////////////// PRIMERA FILA ////////////////////////////////////
// Crea la primera fila para el título. Empiezan en cero
HSSFRow fila = hoja1.createRow((short)0);
// Crea la celda del título
HSSFCell celda = fila.createCell((short)0);
// Pone a la celda el texto y el estilo
celda.setCellValue( new HSSFRichTextString("Gastos del proyecto") );
celda.setCellStyle( crearEstilo( wb, "Tahoma", (short)14, true ));
// Una celda con fecha (el formato debe verse en la documentación de ayuda)
HSSFCell celdaFecha = fila.createCell((short) 3);
celdaFecha.setCellValue(new Date());
HSSFCellStyle estiloFecha = wb.createCellStyle();
estiloFecha.setDataFormat(HSSFDataFormat.getBuiltinFormat("d-mmm-yy"));
celdaFecha.setCellStyle( estiloFecha );
////////////////////////// SEGUNDA FILA ////////////////////////////////////
// Estilo de números alineamiento derecho + separador de miles y de decimales
HSSFCellStyle estiloNumeros = wb.createCellStyle();
estiloNumeros.setAlignment( HSSFCellStyle.ALIGN_RIGHT );
estiloNumeros.setDataFormat(HSSFDataFormat.getBuiltinFormat("#,##0.00"));
// Estilo de % alineamiento derecho + color fondo + formato %
HSSFCellStyle estiloPorc = wb.createCellStyle();
estiloPorc.setAlignment( HSSFCellStyle.ALIGN_RIGHT );
estiloPorc.setFillForegroundColor(HSSFColor.BLUE.index);
estiloPorc.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
estiloPorc.setDataFormat(HSSFDataFormat.getBuiltinFormat("0%"));
// Crea la segunda fila para el gasto
HSSFRow fila2 = hoja1.createRow((short)2);
// Crea la celda de importes con el estilo de números
HSSFCell celdaImporte = fila2.createCell((short)1);
celdaImporte.setCellValue(1000);
celdaImporte.setCellStyle( estiloNumeros );
// Crea la celda de % con su estilo correspondiente
HSSFCell celdaPorc = fila2.createCell((short)2);
celdaPorc.setCellValue(0.8);
celdaPorc.setCellStyle( estiloPorc );
// Crea la celda de FORMULA RESULTADO (IMPORTE * %) con el estilo de números
HSSFCell celdaFormula = fila2.createCell((short)3);
celdaFormula.setCellFormula("B3*C3"); // OJO: sin =
celdaFormula.setCellStyle( estiloNumeros );
// Escribir y cerrar libro
wb.write(archivoSalida);
archivoSalida.close();
System.out.println( "Acaba de crear el archivo " + nomArchivo + " con números y fórmulas");
}
catch (java.io.FileNotFoundException e) {
System.out.println( "No se se puede acceder al archivo " + e.getMessage());
}
catch (Exception e) {
e.printStackTrace();
}
}
/*********************************************************************************
Aspectos nuevos:
- Lee una celda de un archivo
- Duplico el valor y escribo en el mismo archivo donde leí
*********************************************************************************/
public void paso04( String nomArchivo ) {
try {
POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream( nomArchivo ));
HSSFWorkbook wb = new HSSFWorkbook(fs);
HSSFSheet hoja = wb.getSheetAt(0);
HSSFRow fila = hoja.getRow(2);
//// Leo la celda del importe
HSSFCell celda = fila.getCell((short)1);
if (celda == null) {
System.out.println( "La celda seleccionada no tiene nada");
return;
}
double importe = celda.getNumericCellValue();
System.out.println( "Leo y escribo en " + nomArchivo +
": Leo importe (" + importe + "), lo doblo y escribo");
//// Pongo el doble en la celda
celda.setCellValue(importe*2);
// Escribir y cerrar libro
FileOutputStream archivoSalida = new FileOutputStream( nomArchivo );
wb.write(archivoSalida);
archivoSalida.close();
System.out.println( "Acaba de guardar el archivo " + nomArchivo + " modificado");
}
catch (java.io.FileNotFoundException e) {
System.out.println( "No se se puede acceder al archivo " + e.getMessage());
}
catch (Exception e) {
e.printStackTrace();
}
}
}