jueves, 28 de febrero de 2013

Leer y Escribir Objetos en un Fichero.

Buenas amigos, en temas anteriores estuvimos viendo como leer y escribir cadenas y datos primitivos en ficheros. En este nuevo tema, y como culminación al tema de lectura y escritura de ficheros en el disco duro, vamos a ver la escritura y lectura de objetos en ficheros.


Es muy parecido a las situaciones anteriores, así que no deberían de ser un problema entender su funcionamiento. Para realizar la lectura y escritura de objetos vamos a utilizar las siguientes clases:

    • File: Para crear o cargar el archivo.
    • FileInputStream y FileOutputStream: Para leer o escribir los objetos.
    • ObjectInputStream y ObjectOutputStream: Que serán los encargados de manejar la lectura y la escritura de los objetos.
Para este tema voy a hacer un ejemplo, para almacenar personas,  e ir explicándolo poco a poco para que vayamos comprendiendo bien los pasos.

Bien, vamos a empezar creando una clase que encapsule los datos de las personas. Estos datos serán:
    • Nombre
    • Edad
    • DNI
Si no estas muy familiarizado con el encapsulamiento de una clase, visita este tema. Encapsulamiento
Lo primero de todo, es que la clase, y cualquier clase, el cual un objeto suyo vaya a ser escrito o leído del disco, debe ser SIEMPRE Serializable. Esta interfaz no implementa ningún método, solo permite la correcta lectura y escritura de los objetos en el disco. Muy Importante.

Podéis ver, que solo creo los "getters" ya que los datos los paso por el constructor.

Bien, la clase anterior no tiene más historia, simplemente es una clase donde almacenar los datos de la persona. Creamos una nueva clase, donde crearemos 2 métodos, uno para lectura y otro para escritura. Veamoslos:

Escritura:

Los pasos a seguir son:
  1. Crear o cargar un fichero por medio de la clase File.
  2. Se lo pasamos a FileOutputStream para escribir.
  3. Este, se lo pasamos a ObjectOutputStream para que escriba.
  4. Escribimos el objeto en el fichero.
  5. Cerramos ObjectOutputStream.

Un par de cosas, el archivo a crear tiene que tener extensión .obj, y debemos capturar IOException que lanza el método "writeObject(Object o)". FileOutputStream lanza la excepción FileNotFoundException, pero como ya capturamos IOException, no tenemos porque capturarla.

Escribo 3 personas, ya que así, a mi entender, podemos sacarle más sustancia al tema.

Lectura:

Los pasos a seguir son:
  1. Cargar el fichero mediante la clase File.
  2. Se lo pasamos a FileInputStream.
  3. Este se lo pasamos a ObjectInputStream.
  4. Creamos un bucle infinito para leer todos los objetos. Previamente capturamos IOException para la finalización del programa sin errores.
  5. Imprimimos por pantalla todos los datos de los objetos.
  6. Cerramos ObjectInputStream.

Cargamos nuestro fichero en sus respectivas clases, creamos un bucle infinito con el while(true) y capturamos IOException para que cuando el archivo termine de leer objetos y salte, nos muestre por pantalla nuestro dialogo "Fin". En el bloque finally cerramos ObjetInputStream ya que este bloque se ejecuta siempre, salte o no la excepción. También deberéis capturar las excepciones IOException y ClassNotFoundException lanzadas por ObjectInputStream y el método readObject() respectivamente. FileInputStream lanza también FileNotFoundException pero teniendo IOException, no hace falta.

Bien, aquí os dejo la clase entera:

Y aquí el resultado:


Bueno, ya sabéis como leer y escribir objetos, ahora tenéis que practicar y discurrir vosotros en las situaciones que os viene mejor utilizarlo y como utilizarlo.

Un saludo.



18 comentarios:

  1. disculpa cada vez que corres el programa se crea otro archivo o sigue escribiendo donde se quedo

    ResponderEliminar
    Respuestas
    1. Muy buenas, el archivo se sobrescribe todo el tiempo, pero si notas que no funciona todo lo correcto que debería o que te repite información, siempre puedes hacer un file.delete(); y volver a crearlo, pero vamos, nunca tuve que hacerlo a menos que tuviese que borrarlo por asuntos más específicos Te crea un archivo y juega siempre con ese archivo, no te encontraras un "archivo.obj" y un "archivo(1).obj", si es a lo que te refieres. Siempre sobrescribe.

      Un saludo

      Eliminar
  2. muchas gracias por contestarme pero a la hora que quiero leer el archivo solo me lee lo ultimo que guarde no me lle todo lo que tenia anteriormente en el archivo y lo que quisiera es crear un archivo y guardar los objetos hay pero que no los destruya cada vez que le meto algo nuevo y a la hora de llerlo que me lea todo el archivo completo no solo lo ultim oque meti

    ResponderEliminar
    Respuestas
    1. Buenas, como ya dije el archivo.obj sobrescribe el contenido Supongamos que tienes un archivo que almacena, por ejemplo, vehículos, y supongamos que tienes almacenados un camión, un coche y una moto. Bien, tu ahora quieres agregar una bicicleta y al almacenarla en tu archivo te borra los 3 vehículos que tienes y te pone la bicicleta, eso es lo que te ocurre a ti, bien, lo que tiees que hacer cada vez que quieres agregar un nuevo vehículo a tu archivo es obtener la información del archivo, los 3 vehículos, agregar a esos 3 vehiculos la bicicleta y volver a guardar, con que lo que te guardará los 4 archivos. Esto yo lo hago con ayuda de colecciones, mas concretamente ArrayList, voy a editar el tema y voy a agregar un apartado para que veas como poder hacerlo sin problemas, ya que me puede quedar un poco extenso, permitiéndote agregar, modificar y borrar distintos objetos que tu tengas almacenados. Lo tendré lo antes posible, si no hoy, mañana. Un saludo.

      Eliminar
  3. Buenas, quiero guardar un objeto del tipo PrintJob y me da error de esta forma,¿sabes por que?

    ResponderEliminar
    Respuestas
    1. Buenas Floppy;

      Para guardar el objeto de una clase en un fichero, esta clase debe ser implementada por Serializable, ya que es la que permite leer y escribir objetos en disco, si no implementas esta interfaz no te va a dejar guardar el objeto y te saltará una exception. Por lo que tengo entendido PrintJob no implementa serializable, por lo que tendrás que tomar otro camino para ello:

      1* Crear una clase que herede de PrintJob e implemente Serializable

      2*Almacenar los datos de PrintJob en otra clase que implemente serializable y pasárselos posteriormente a PrintJob cuando sea requerido.

      Esto es lo que puedo deducir de la información que me has enviado, si no es tu caso, y tienes todos los objetos que guardas en fichero implementando serializable, me vas a tener que dar algo más de información, como el volcado de pila o el código.

      Un saludo y suerte.

      Eliminar
    2. Gracias Bartolomé,
      lo que hice fue crear una clase con todos los datos de los que se componía, luego creé un método clonar para cuando recuperara el objeto desde el fichero volviera a meter los datos y luego volvía a crear el job. No creo que sea ni por asomo la mejor solución, pero al menos funciona.

      Un saludo.

      Eliminar
  4. Saludos. espero y me puedar ayudar, inbgreso los datos de los pacientes en un archivo binario (n. de expediente, apellidos, nombres, dni, direccion, telefono y fotografia), los guarda bienb, pero cuando hago la consulta a traves del numero de expediente solo me muestra el ultimo ingresado. aqui les dejo el codigo de ingreso y consulta respectivamente:

    private void btcGuardarActionPerformed(java.awt.event.ActionEvent evt) {
    // TODO add your handling code here:
    Object nombreArchivo = archivo;
    System.out.println(nombreArchivo);
    try{
    ObjectOutputStream fileout = new ObjectOutputStream(new FileOutputStream((String) nombreArchivo));
    fileout.writeObject(txtNroExpediente.getText());
    fileout.writeObject(txtDni.getText());
    fileout.writeObject(txtApellidos.getText());
    fileout.writeObject(txtNombres.getText());
    fileout.writeObject(txtDireccion.getText());
    fileout.writeObject(txtTelefono.getText());
    fileout.writeObject(lblFoto.getIcon());
    JOptionPane.showMessageDialog(null, "Los datos del paciente se guardaron corecttamente...");
    if(fileout!=null){
    fileout.close();
    }
    }catch(IOException e){}
    desactivarTextFields();
    btcGuardar.setEnabled(false);
    btcNuevo.setEnabled(true);
    btcBuscar.setEnabled(false);
    }


    private void btcBuscarActionPerformed(java.awt.event.ActionEvent evt) {
    // TODO add your handling code here:
    Object nombreArchivo = archivo;
    try{
    try (ObjectInputStream filein = new ObjectInputStream(new FileInputStream((String) nombreArchivo))){
    Object expediente = filein.readObject();
    if (txtNroExpediente.getText().equals(expediente)){
    Object dni = filein.readObject();
    Object apellidos = filein.readObject();
    Object nombres = filein.readObject();
    Object direccion = filein.readObject();
    Object telefono = filein.readObject();
    Object foto = filein.readObject();
    txtNroExpediente.setText((String) expediente);
    txtDni.setText((String) dni);
    txtApellidos.setText((String) apellidos);
    txtNombres.setText((String) nombres);
    txtDireccion.setText((String) direccion);
    txtTelefono.setText((String) telefono);
    lblFoto.setIcon((Icon) foto);
    }
    if(filein!=null){
    filein.close();
    }
    } catch (ClassNotFoundException ex) {
    Logger.getLogger(JDPacientes.class.getName()).log(Level.SEVERE, null, ex);
    }
    }catch(IOException e){}
    }

    ResponderEliminar
    Respuestas
    1. Buenas Victor;

      Cada vez que guardas un paciente, creas un fichero que sobreescribe al anterior, por lo que siempre tendrás un fichero con los datos del último paciente guardado.

      La idea es crear un fichero y guardar todos los pacientes que tengas de golpe, (eso lo consigues con un for o un iterator).

      Una vez creado y guardado tu fichero, con digamos 30 pacientes, si quieres agregar algún otro, tienes que obtener todos los datos que tengas en tu fichero, agregarle a tus 30 pacientes el nuevo y volver a guardarlos todos, si no, como ya te he dicho, te va a sobreescribir el archivo, y si solo has guardado un paciente, solo vas a tener un paciente en ese fichero.

      Un saludo.

      Eliminar
  5. Buenas Bartolomé.

    Si te sirve utiliza FileOutputStream fos = new FileOutputStream(String, true); para que no sobreescriba lo que ya tengas guardado en el fichero

    ResponderEliminar
  6. como se puede eliminar un elemnto de la lista que ya esta gurdado ¿? gracias por tu apoyo

    ResponderEliminar
  7. como se puede eliminar un elemnto de la lista que ya esta gurdado ¿? gracias por tu apoyo

    ResponderEliminar
  8. como puedo sumar valores guardados en un archivo ?

    ResponderEliminar
  9. Hola, como estas? Estaba intentando generar un metodo basandome en tu post pero me encuentro con un error.
    Te dejo el codigo a ver si me podes dar una mano.

    public ArrayList LevantarArchivo() {
    ObjectInputStream ois = null;
    ArrayList ConAux= null;
    try {
    if(!file.exists()){
    file.createNewFile();
    }
    FileInputStream fis = new FileInputStream (file);
    ois = new ObjectInputStream (fis);
    while(true){

    ConAux=(ArrayList) ois.readObject();

    }

    } catch (IOException | ClassNotFoundException e){
    e.printStackTrace();
    System.out.println("FIN\n");
    }
    return ConAux;

    }

    ResponderEliminar
  10. Hola qué tal...
    Yo no fui...
    El barto (Mentira soy el Uriel)
    (O tal vez el Ivan)
    Quien sabe...

    ResponderEliminar
  11. Excelente la informacion es muy clara y util Gracias Amigo

    ResponderEliminar
  12. Buen aporte. Lo de meter las personas en una lista como serí?

    ResponderEliminar