Serialización#
Introducción#
En el manejo de datos, es común encontrarse con la necesidad de guardar y recuperar información de manera eficiente. Para lograr esto, Java proporciona herramientas para serialización y manejo de archivos. La serialización permite convertir un objeto en una secuencia de bytes para almacenarlo o transmitirlo, mientras que el manejo de archivos permite leer y escribir datos de archivos en el sistema.
Esta clase explorará en detalle los conceptos fundamentales de serialización, deserialización, y operaciones de archivos en Java, proporcionando ejemplos prácticos para entender su funcionamiento.
Objetivos#
Comprender el concepto de serialización en Java y su importancia en el almacenamiento y transmisión de objetos.
Aplicar operaciones de serialización y deserialización en objetos de Java.
Entender el manejo de archivos en Java, incluyendo la lectura y escritura de archivos.
Implementar ejemplos prácticos que combinen la serialización y manejo de archivos en Java.
Serialización en Java#
La serialización es el proceso de convertir un objeto en una secuencia de bytes, lo que permite que se almacene o se envíe a través de una red. En Java, para que un objeto sea serializable, la clase debe implementar la interfaz Serializable
.
No todos los objetos pueden escribirse en un flujo de salida. Los objetos que pueden ser escritos se dice que son serializables. Un objeto serializable es una instancia de la interfaz java.io.Serializable, por lo que la clase del objeto debe implementar Serializable.
La interfaz Serializable es una interfaz marcadora. Como no tiene métodos, no necesitas añadir código adicional en tu clase que implemente Serializable. La implementación de esta interfaz permite que el mecanismo de serialización de Java para automatizar el proceso de almacenamiento de objetos y matrices.
Clases y Objetos


import java.io.*;
public class TestObjectOutputStream {
public static void main(String[] args) throws IOException {
try ( // Create an output stream for file object.dat
ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("object.dat"));
// Se puede reemplazar y mejorar el rendimiento con
// ObjectOutputStream output = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("object.dat")));
) {
// Write a string, double value, and object to the file
output.writeUTF("John");
output.writeDouble(85.5);
output.writeObject(new java.util.Date());
}
}
}
Ejemplo básico de serialización#
import java.io.*;
// Clase que implementa Serializable
class Persona implements Serializable {
private String nombre;
private int edad;
public Persona(String nombre, int edad) {
this.nombre = nombre;
this.edad = edad;
}
@Override
public String toString() {
return "Nombre: " + nombre + ", Edad: " + edad;
}
}
public class SerializacionEjemplo {
public static void main(String[] args) {
Persona persona = new Persona("Juan", 30);
// Serializar el objeto
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("persona.ser"))) {
oos.writeObject(persona);
System.out.println("Objeto serializado correctamente.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
En este ejemplo, la clase Persona
implementa Serializable
, lo que permite que los objetos de esa clase puedan ser serializados. El archivo persona.ser
contendrá la información del objeto en formato de bytes.
// Prueba el texto aquí
Para verificar su impacto en otro tipo de objetos que contienen elementos de diferente tipo de dato (arreglos, pilas, colas, etc) probemos la serialización de listas.
Implementa y prueba el código Listing 17.7 TestObjectStreamForArray.java del libro guía, página dccxxxiii o 710.
// Implementa la clase TestObjectStreamForArray
Deserialización en Java#
La deserialización es el proceso inverso de la serialización, donde una secuencia de bytes se convierte de nuevo en un objeto Java.

import java.io.*;
public class TestObjectInputStream {
public static void main(String[] args)
throws ClassNotFoundException, IOException {
try ( // Create an input stream for file object.dat
ObjectInputStream input = new ObjectInputStream(new FileInputStream("object.dat"));
) {
// Read a string, double value, and object from the file
String name = input.readUTF();
double score = input.readDouble();
java.util.Date date = (java.util.Date)(input.readObject());
System.out.println(name + " " + score + " " + date);
}
}
}
Ejemplo básico de deserialización#
import java.io.*;
public class DeserializacionEjemplo {
public static void main(String[] args) {
// Deserializar el objeto
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("persona.ser"))) {
Persona persona = (Persona) ois.readObject();
System.out.println("Objeto deserializado: " + persona);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
En este ejemplo, el archivo persona.ser
se lee y el objeto persona
se reconstruye a partir de los bytes guardados.
DataInputStream/DataOutputStream#
DataInputStream
lee bytes del flujo y los convierte en valores de tipo primitivo o cadenas. DataOutputStream
convierte valores de tipo primitivo o cadenas en bytes y envía los bytes al flujo.
DataInputStream
extiende FilterInputStream
e implementa la interfaz DataInput
. DataOutputStream
extiende FilterOutputStream
e implementa la interfaz DataOutput
.



// Prueba el texto aquí
E/S de Texto vs a E/S Binaria#
La E/S binaria no implica codificación ni descodificación, por lo que es más eficiente que la E/S de texto.
Los ordenadores no distinguen entre archivos binarios y archivos de texto. Todos los archivos se almacenan en formato binario y, por tanto, todos los archivos son esencialmente binarios. La E/S de texto se basa en la E/S binaria para proporcionar un nivel de abstracción para la codificación y descodificación de caracteres. La codificación y descodificación se realizan automáticamente para la E/S de texto.
La clase abstracta
InputStream
es la clase raíz para la lectura de datos binarios, y la clase abstractaOutputStream
es la clase raíz para escribir datos binarios.
El diseño de las clases de E/S de Java es un buen ejemplo de aplicación de la herencia, donde las operaciones comunes se generalizan en superclases, y las subclases proporcionan operaciones especializadas.
import java.io.*;
public class TestDataStream {
public static void main(String[] args) throws IOException {
try ( // Create an output stream for file temp.dat
DataOutputStream output = new DataOutputStream(new FileOutputStream("temp.dat"));
) {
// Write student test scores to the file
output.writeUTF("John");
output.writeDouble(85.5);
output.writeUTF("Susan");
output.writeDouble(185.5);
output.writeUTF("Kim");
output.writeDouble(105.25);
}
try ( // Create an input stream for file temp.dat
DataInputStream input = new DataInputStream(new FileInputStream("temp.dat"));
) {
// Read student test scores from the file
System.out.println(input.readUTF() + " " + input.readDouble());
System.out.println(input.readUTF() + " " + input.readDouble());
System.out.println(input.readUTF() + " " + input.readDouble());
}
}
}
// Prueba el texto aquí
Ejercicio#
Taller 5
Primera Parte
Implementa un proyecto de java que resuelva el taller FilesSerializationWorkshop.md. Coloca los mismos nombres a las clases y métodos siguiendo la guía. Realiza tantas clases como necesites y recuerda que el código de la página web puede ser creado desde ChatGPT.
Segunda Parte
Implementa y prueba el código del libro guía, Y. Daniel, que copia archivos, código 17.4 Copy.java.
. Deben modificar la acción de la clase para que no sea la misma del libro, cambiar y agregar algunas líneas de código.
Tercera Parte
Implementa y prueba el código del libro guía, Y. Daniel, que implementa el Acceso aleatorio de archivos, código 17.8 ImpTestRandomAccessFile.java
. Deben modificar la acción de la clase para que no sea la misma del libro, cambiar y agregar algunas líneas de código.
Conclusión#
La serialización y el manejo de archivos son fundamentales para el desarrollo de aplicaciones en Java que requieren persistencia y comunicación de datos. La serialización permite convertir objetos en secuencias de bytes, facilitando su almacenamiento en archivos o su transmisión a través de redes. Esta técnica es clave cuando se necesita mantener el estado de un objeto más allá de la ejecución de un programa. Por otro lado, el manejo de archivos permite leer y escribir datos desde y hacia archivos, lo cual es esencial para cualquier aplicación que interactúe con sistemas de almacenamiento.
Dominar estas técnicas no solo mejora la capacidad de un programador para crear aplicaciones que gestionen datos de manera efectiva, sino que también le permite construir soluciones más robustas y eficientes, asegurando que los datos persistan entre ejecuciones y que puedan ser transferidos entre diferentes sistemas de forma segura y controlada.
Recursos Adicionales#
Libros#
Y. Daniel Liang. «Introduction to Java Programming and Data Structures, Comprehensive Version». Addison Wesley. Edición 12 (2019). Capítulo 17.
Bloch, Joshua. Effective Java. Addison-Wesley, 2008.
Eckel, Bruce. Thinking in Java. Prentice Hall, 2006.