Desenpolvando un poco temas de Java, hoy traigo un pequeño howto para guardar datos que tenemos representados en clases, en ficheros, sin complicarnos demasiado la vida. Es decir, a veces, necesitamos algo rápido para guardar en ficheros o para transmitir información por la red.
La clase Java, el objeto, debe implementar la interfaz Serializable, y así será fácilmente guardable como fichero de texto. Al hacer un objeto serializable, de forma automática se podrá convertir en una cadena de texto, con lo que podremos guardar este contenido fácilmente en un fichero, transmitirlo por la red, en una BD, etc.. ¡vamos a grano!
El código
Marco en negrita los códigos que hacen que un objeto se haga serializable. Aquí se almacenan dichos objetos en un array, así lo que se guarda es el array y de una tacada se guardan todos los objetos que haya.
De igual forma se recuperan del disco para comprobar qué tal se han guardado:
import java.util.ArrayList;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.Serializable;
public class Serializando {
@SuppressWarnings({ "unchecked" })
public static void main(String[] arg) {
ArrayList <Objeto> arrayList1 = new ArrayList <Objeto>();
ArrayList <Objeto> arrayList2;
System.out.println("Datos que vamos a escribir en el fichero:");
for(int i = 0; i < 10; i++) {
Objeto nuevoObjeto = new Objeto("Cadena" + i);
arrayList1.add(nuevoObjeto);
System.out.println( "arrayList1[" + i + "] = " + arrayList1.get(i) );
}
try {
System.out.print("Guardando ArrayList en el fichero objetos.dat.. ");
ObjectOutputStream escribiendoFichero = new ObjectOutputStream(
new FileOutputStream("objetos.dat") );
escribiendoFichero.writeObject(arrayList1);
escribiendoFichero.close();
System.out.println("ok!");
System.out.print("Leyendo ArrayList del fichero objetos.dat.. ");
ObjectInputStream leyendoFichero = new ObjectInputStream(
new FileInputStream("objetos.dat") );
arrayList2 = ( ArrayList <Objeto> )leyendoFichero.readObject();
leyendoFichero.close();
System.out.println("ok!");
System.out.println("Datos leídos del fichero:");
for(int i = 0; i < arrayList2.size(); i++) {
System.out.println( "arrayList2[" + i + "] = " + arrayList2.get(i) );
}
} catch (Exception e) {
System.out.println( e.getMessage() );
}
}
}
class Objeto implements Serializable {
private String _dato;
public Objeto (String dato) {
this._dato = dato;
}
public String toString() {
return this._dato;
}
}
Ejecutando
Ahora para ejecutarlo tenemos que ejecutar desde línea de comandos lo siguiente:
$ javac Serializando.java
$ java Serializando
Si todo ha ido bien tenemos que ver en pantalla lo siguiente:
Datos que vamos a escribir en el fichero:
arrayList1[0] = Cadena0
arrayList1[1] = Cadena1
arrayList1[2] = Cadena2
arrayList1[3] = Cadena3
arrayList1[4] = Cadena4
arrayList1[5] = Cadena5
arrayList1[6] = Cadena6
arrayList1[7] = Cadena7
arrayList1[8] = Cadena8
arrayList1[9] = Cadena9
Guardando ArrayList en el fichero objetos.dat.. ok!
Leyendo ArrayList del fichero objetos.dat.. ok!
Datos leídos del fichero:
arrayList2[0] = Cadena0
arrayList2[1] = Cadena1
arrayList2[2] = Cadena2
arrayList2[3] = Cadena3
arrayList2[4] = Cadena4
arrayList2[5] = Cadena5
arrayList2[6] = Cadena6
arrayList2[7] = Cadena7
arrayList2[8] = Cadena8
arrayList2[9] = Cadena9
Ya está no tiene más historia. Espero que sirva. ¡Un saludo!
Muy útil. Llevo varias horas tratando de encontrar la forma de guardar dinámicamente objetos en mi fichero y poder leerlos todos, y lo logré hasta ahora con ayuda de este código. Muchísimas gracias!
No hay de que Merelyn, gracias por dejar un comentario!
Me alegro de que te haya ayudado.
Saludos.
Hola, deseo realizar que un programa pueda un usuario baje un PDF individual y lo guarde en su PC, . Vos me puedes ayudar en eso??
Mb tu propuesta por eso te escribo.
Gracias.
Hola Adriana.
No acabo de entender bien la especificación de tu comentario. Pero gracias por dejar un comentario. Y he encontrado éste código fuente en Java que te podría ayudar:
try (BufferedInputStream inputStream = new BufferedInputStream(new URL(«http://www.dominiodelaweb.com/nombre-fichero.pdf»).openStream());
FileOutputStream fileOS = new FileOutputStream(«/Users/username/Documents/nombre-fichero.pdf»)) {
byte data[] = new byte[1024];
int byteContent;
while ((byteContent = inputStream.read(data, 0, 1024)) != -1) {
fileOS.write(data, 0, byteContent);
}
} catch (IOException e) {
// handles IO exceptions
}
..lo he sacado de https://stackabuse.com/how-to-download-a-file-from-a-url-in-java/. Espero que sirva.
Un saludo!
Y como se haría para cargar ese mismo archivo de datos en el arraylist1
En la parte donde se carga en arrayList2 lo tienes. Sería lo mismo pero poniendo arrayList1.
Un saludo José.
Que va tengo un código como este y no me deja.
El arraylist que guardo y cargo es este.
ArrayList Usuarios = new ArrayList();
case 4:
System.out.print(«Guardando datos en el fichero datos.dat.. «);
ObjectOutputStream escribiendoFichero = new ObjectOutputStream(new FileOutputStream(«datos.dat»));
escribiendoFichero.writeObject(Usuarios);
escribiendoFichero.close();
System.out.println(«Datos Guardados con exito!»);
break;
case 5:
System.out.print(«Leyendo ArrayList del fichero datos.dat.. «);
ObjectInputStream leyendoFichero = new ObjectInputStream(new FileInputStream(«datos.dat»));
Usuarios = (ArrayList) leyendoFichero.readObject(); //En esta línea me da error el codigo
leyendoFichero.close();
System.out.println(«ok!»);
System.out.println(«Datos leídos del fichero:»);
break;
Creo que falla porque no has declarado el tipo de objeto que guardas en la lista, ni luego al cargarlo desde fichero el casting de lo que lees:
..
ArrayList <Usuario> usuarios = new ArrayList <Usuario>();
..
escribiendoFichero.writeObject(usuarios);
..
usuarios = ( ArrayList <Usuario> ) leyendoFichero.readObject();
..
Un saludo José.
Como haría para cargar un archivo.dat ya serializado en una Jtable y también guardar los elementos que ya se agregaron a la Jtable en un archivo.dat ya serializado??
Hola Pipe!
Aquí escribí algo sobre esto:
https://jnjsite.com/java-swing-9-la-madre-del-cordero-el-jtable/
https://jnjsite.com/java-swing-10-jtable-segunda-parte-un-poco-mas-sobre-tablas/
La idea es que enlazas un DefaultTableModel al JTable, entonces puedes sacar los datos del fichero y los cargas al modelo para que se vean en la tabla. Así a su vez también puedes sacarlos de la tabla luego, para guardarlos en el fichero.
Saludos.
Yo obtengo un error que no me deja correr el programa, es el siguiente…..
local class incompatible: stream classdesc serialVersionUID = 6529685098267757690, local class serialVersionUID = 8603723807187381908
Hola Lauro!
Muchas gracias por dejar un comentario.
Acabo de probarlo con OpenJDK 11 desde GNU/Linux y parece que funciona todo correcto.
Puede ser necesario que necesites revisar esto: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/Serializable.html
..el valor de serialVersionUID previene de errores a la hora de serializar y deserializar objetos, conviene añadirlo.
Saludos.
Pero el casting da un Warning de unsafety cast y para ello hay que hacer un cast sin declarar el tipo de dato arraylist2 = (ArrayList())
LeyendoFichero.readObject() ;
Y luego recorres el arraylist2 y añades los objetos del arraylist2 al arraylist1 con un casting al tipo de Objeto, así
arraylist1.add((Objeto) arraylist2.get(i);
Buenos días Codexna!
Muchas gracias por el aporte!
Tengo este código y aunque ya busque la manera de arreglarlo no me sale, me podría ayudar
1) PersonaBean
package mx.startonline.beans;
import java.io.Serializable;
public class PersonaBean implements Serializable {
private String Nombre;
private String Apellido;
private String edoCivil;
private int edad;
public PersonaBean() {
}
public String getNombre() {
return Nombre;
}
public void setNombre(String nombre) {
Nombre = nombre;
}
public String getApellido() {
return Apellido;
}
public void setApellido(String apellido) {
Apellido = apellido;
}
public String getEdoCivil() {
return edoCivil;
}
public void setEdoCivil(String edoCivil) {
this.edoCivil = edoCivil;
}
public int getEdad() {
return edad;
}
public void setEdad(int edad) {
this.edad = edad;
}
}
2)RecibePersona
package mx.startonline.beans;
public class RecibePersona {
public RecibePersona() {
RegistroPersona registroPersona = new RegistroPersona();
PersonaBean personaBean = registroPersona.creaPersona();
System.out.println(«Nombre: » + personaBean.getNombre() );
System.out.println(«Apellidos: » + personaBean.getApellido() );
System.out.println(«Edo Civil: » + personaBean.getEdoCivil() );
System.out.println(«Edad: » + personaBean.getEdad() );
}
public static void main(String[] args) {
new RecibePersona();
}
}
3) RegistroPersona
package mx.startonline.beans;
public class RegistroPersona {
PersonaBean personaBean;
protected PersonaBean creaPersona() {
personaBean = new PersonaBean();
personaBean.setNombre(«Leonardo»);
personaBean.setApellido(«PalaciosMartinez»);
personaBean.setEdoCivil(«Viudo»);
personaBean.setEdad(19);
return personaBean;
}
}
Buenas tardes Fátima!
No veo el problema, tu código lo estoy probando en mi ordenador y funciona perfectamente. Se ve por pantalla lo siguiente al lanzar el main:
Nombre: Leonardo
Apellidos: PalaciosMartinez
Edo Civil: Viudo
Edad: 19
Saludos.
Hola que tal. Sabes he estdo utilizando una clase, por ejemplo persona, y al guardar los registros los hago guardando bytes, o enteros o boolean, osea para recuperar un registro hago como 10 lecturas, pero conforme iba avanzando mi aplicacion la cantidad de registros aumenta y por ende la cantidad de lecturas tambien. Ahora cuando corro mi aplicacion y muestro los registros guaradados anterirormente, el ordenador se demora como 2 segundos en mostrarlos en mi JTable, (hablo de 20 registros por lo menos ). Entonces conforme haga mas registros, ala hora de leerlos va a demorar mas. Ahora que me recomiendas para guardar y leerlos? Seria de Serializar cada clase a guardar? Seria mas rapida o no cambia mucho? Entonces debo usar base de datos para una lectura mad rapida?
Hola Eduardo.
Pienso que estás en lo correcto. El guardado y recuperación desde ficheros, si es para un uso intensivo, o para cantidades muy grandes de información, mejor si lo haces usando una base de datos. El serializar objetos viene bien para ficheros de configuraciones, usos puntuales pero no intensos de esta información, también se usa para transmitir información entre procesos o entre ordenadores por red, etc.. Es decir, para un JTable con mucha información mejor usar una base de datos.
Saludos.