// // // // // // //

jueves, 8 de enero de 2015

Construyendo tu programa IV: Persistencia I: Ficheros

    Como es normal, un programa de gestión que cuando lo cierras no guarda datos no es muy útil, así que toca hablar de la persistencia. Empezaremos por la persistencia en ficheros. Para empezar hay que hablar del concepto de Stream. Un Stream es un flujo de datos entre dos aplicaciones, en este caso el sistema de archivos. Hay varios Objetos Stream en java que representan, hoy hablaré solo del ObjectStream, que guarda objetos. Hay otros que se encargan de tipos primitivos etc.. pero eso lo veré en otra entrada.



  Empezaremos por crear una clase que se encargará de la persistencia, yo la he llamado GestoraPersistenciaFicheros y en ella un campo estático con la ruta del fichero donde se guardarán los datos, en mi caso: "./Empleados.obj". Como ya he dicho usaré el ObjectStream y para utilizarlo tendremos que implementar la interface Serializable con su número serialVersionUID, que indica la versión de la clase con la que el objeto se guardará, y crear un ObjectOutputStream y después serializar en el fichero.Para ello usaremos el método writeObject(). Este es el código:

public class Empleado implements Serializable{
    
    private static final long serialVersionUID = 8799656478674716638L;

    Así quedaría el empleado, ahora vamos con la gestora:

public class GestoraPersistenciaFicheros {
    
    // La ruta del fichero donde se guardará
    private static final String ruta = "./Empleados.obj";
    
    public static boolean guardarEmpleados(ArrayList<Empleado> e){
        
        // Esto es un try de recursos, sirve para que java los cierre solos ante cualquier error 
        // y asegurarse de que siempre se haga
        try(ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(ruta))){
            
            out.writeObject(e);
            
            // En este caso no sería necesario pero lo dejo para que tengáis en cuenta el método flush(),
            // por que si usamos un stream con buffer puede que sea fuente de problemas el no usarlo
            out.flush();
        } catch (IOException ex) {
            
            Logger.getLogger(GestoraPersistenciaFicheros.class.getName()).log(Level.SEVERE, null, ex);
            return false;            
        }
        
        return true;
    }
    
    public static ArrayList<Empleado> recuperarEmpleados(){
        
        // La inicializamos para que nunca sea null
        ArrayList<Empleado> devolver = new ArrayList();
        // Esto es un try de recursos, sirve para que java los cierre solos ante cualquier error 
        // y asegurarse de que siempre se haga
        try(ObjectInputStream in = new ObjectInputStream(new FileInputStream(ruta))){
            
            devolver.addAll((ArrayList<Empleado>)in.readObject());
            
            // En este caso no sería necesario pero lo dejo para que tengais en cuenta el método flush(),
            // por que si usamos un stream con buffer puede que sea fuente de problemas el no usarlo
            
        } catch (IOException | ClassNotFoundException ex) {
            
            Logger.getLogger(GestoraPersistenciaFicheros.class.getName()).log(Level.SEVERE, null, ex);
            // Si salta una excepción devolverá null, eso habrá que tenerlo en cuenta
            return null;            
        }
        
        return devolver;
    }
}

   Como veis es muy sencillo, además, la clase sirve para enmascarar el funcionamiento de la persistencia por lo que, después de implementarla, podríamos cambiar el código para que se almacenara en una base de datos, y no habría que cambiar nada más de la clase. Ahora lo implementamos:

    Primer cambio en la Gestora, al inicializarla por primera vez recuperamos los datos y actualizar el numero del siguiente empleado:
public static GestoraEmpleados dameGestora(){
        
        if(unicaGestora == null){
            unicaGestora = new GestoraEmpleados();
            
            ArrayList<Empleado> rec = GestoraPersistenciaFicheros.recuperarEmpleados();
            if(rec != null){
                unicaGestora.addAll(rec);            
                unicaGestora.actualizarNumeroEmpleado();
            }
                
        }
        
        return unicaGestora;
    }
// resto de la clase...

// antes del final
public final void actualizarNumeroEmpleado(){
        
        for(Empleado e : this){
            
            nSiguienteEmpleado = (e.getId()+1 > nSiguienteEmpleado)? e.getId()+1: nSiguienteEmpleado;
        }
    }
    Si te gustan las lambdas prueba esto en vez del bucle en el método anterior:
this.stream().forEach((Empleado e) -> {
            nSiguienteEmpleado = (e.getId()+1 > nSiguienteEmpleado)? e.getId()+1: nSiguienteEmpleado;
        });
    El segundo en la ventana, en el método del evento WindowClosing (en NetBeans click derecho en el frame > eventos > window > WindowClosing) guardaremos los datos:
private void formWindowClosing(java.awt.event.WindowEvent evt) {                                   
        
        // Como sabemos que la gestora es un ArrayList<Empleado> queda así de simple (Gracias a la orientación a objetos)
        GestoraPersistenciaFicheros.guardarEmpleados(gestora);
} 
    ¡Importante! La primera vez que arranque el programa, como no existe el fichero te capturará la Excepción EOFException, que deriva de IOException, pero como al cerrar la ventana creamos el fichero no hay más problema.
    Hasta aquí la persistencia en ficheros para nuestro programa.Hablaré más adelante de los Stream. Espero que haya sido útil, si opináis que debería añadir algo o cambiar algo de lo que he puesto, comentad.

No hay comentarios:

Publicar un comentario