Escritura y Lectura#
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.
Lectura y Escritura de Archivos#
Java proporciona varias clases para trabajar con archivos, como FileInputStream
, FileOutputStream
, BufferedReader
, y BufferedWriter
. A este proceso se le suele conocer por E/S de Texto (Text I/O)
¿Cómo Java lee y escribe archivos?

Texto vs Binarios

BufferedInputStream/BufferedOutputStream#
BufferedInputStream
/BufferedOutputStream
puede utilizarse para acelerar la entrada y salida reduciendo el número de lecturas y escrituras en disco. Con BufferedInputStream
, todo el bloque de datos del disco se lee una vez en el búfer de la memoria. Los datos individuales son entonces cargados a tu programa desde el buffer, como se muestra en la Figura 17.12a. Usando BufferedOutputStream
, los datos individuales se escriben primero en el buffer de la memoria. Cuando el buffer está lleno, todos los datos en el buffer se escriben en el disco una vez, como se muestra en la Figura 17.12b.


DataOutputStream output = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("temp.dat")));
Esta clase es muy completa y robusta, sin embargo, usarla requiere de experticie. Además de esta gran clase, existen otras formas, métodos y clases, que permiten hacer la escritura y lectura de archivos de forma más amigable BufferedReader
y BufferedWriter
.

Ejemplo de escritura en archivo#
import java.io.*;
public class EscrituraArchivo {
public static void main(String[] args) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter("archivo.txt"))) {
writer.write("Este es un ejemplo de escritura en un archivo.");
System.out.println("Texto escrito en el archivo.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
// Prueba el texto aquí
Existen muchas clases de E/S para diversos fines. En general, se pueden clasificar en clases de entrada y clases de salida. Una clase de entrada contiene los métodos para leer datos, y una clase de salida contiene los métodos para escribir datos. PrintWriter
es un ejemplo de una clase de salida que suele utilizar mucho para escribir archivos de html o css para páginas web, y Scanner
es un ejemplo de una clase de entrada. El siguiente código crea un objeto de entrada para el archivo temp.txt y lee datos del archivo:
PrintWriter output = new PrintWriter("temp.txt");
output.print("Java 101");
output.print("Java 102");
output.close();
// Leer el archivo utilizando Scanner
Scanner input = new Scanner(new File("temp.txt"));
System.out.println(input.nextLine());
Java 101Java 102
Clases de E/S Binarios#
El InputStream abstracto es la clase raíz para la lectura de datos binarios, y el OutputStream abstracto es la clase raíz para la escritura de datos binarios.


FileInputStream/FileOutputStream#
FileInputStream
/FileOutputStream
son para leer/escribir bytes de/a archivos. Todos los métodos de estas clases se heredan de InputStream
y OutputStream
. FileInputStream
/FileOutputStream
no introducen nuevos métodos. Para construir un FileInputStream
, utilice los constructores mostrados en la Figura 17.6. Se producirá una java.io.FileNotFoundException
si se intenta crear un FileInputStream
con un fichero inexistente.


Nota
Los datos de texto se leen con la clase Scanner
y se escriben con la clase PrintWriter
.
DataInputStream input = new DataInputStream(new BufferedInputStream(new FileInputStream("temp.dat")));
import java.io.*;
public class TestFileStream {
public static void main(String[] args) throws IOException {
try (
// Create an output stream to the file
FileOutputStream output = new FileOutputStream("temp.dat"); // output stream
) {
// Output values to the file
for (int i = 1; i <= 10; i++)
output.write(i);
}
try (
// Create an input stream for the file
FileInputStream input = new FileInputStream("temp.dat"); // input stream
) {
// Read values from the file
int value;
while ((value = input.read()) != -1) // input
System.out.print(value + " ");
}
}
}
// Prueba el código aquí
Ejemplo de lectura de archivo#

DataInputStream input = new DataInputStream(new BufferedInputStream(new FileInputStream("temp.dat")));
import java.io.*;
public class LecturaArchivo {
public static void main(String[] args) {
try (BufferedReader reader = new BufferedReader(new FileReader("archivo.txt"))) {
String linea;
while ((linea = reader.readLine()) != null) {
System.out.println(linea);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
// Prueba el texto aquí
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í
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.