Docsity
Docsity

Prepara tus exámenes
Prepara tus exámenes

Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity


Consigue puntos base para descargar
Consigue puntos base para descargar

Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium


Orientación Universidad
Orientación Universidad


Manejo de Archivos y Flujos en Java: Guía Detallada, Guías, Proyectos, Investigaciones de Programación Java

Este documento explora el manejo de archivos y flujos en java, cubriendo desde la introducción a los archivos de texto de acceso secuencial hasta la serialización de objetos. Se detallan las clases e interfaces nio para obtener información de archivos y directorios, así como el uso de jfilechooser para la apertura de archivos. Incluye ejemplos prácticos y consejos para prevenir errores, ofreciendo una guía completa para el almacenamiento y procesamiento de datos en java. Útil para estudiantes y profesionales de la informática que deseen profundizar en el manejo de archivos en java, proporcionando una base sólida para el desarrollo de aplicaciones que requieran persistencia de datos. Se abordan temas como la creación, lectura y actualización de archivos, así como la serialización y deserialización de objetos, ofreciendo una visión completa del tema.

Tipo: Guías, Proyectos, Investigaciones

2023/2024

Subido el 25/08/2025

dinawell
dinawell 🇵🇪

1 documento

1 / 41

Toggle sidebar

Esta página no es visible en la vista previa

¡No te pierdas las partes importantes!

bg1
TM
Paul Deitel
Deitel & Associates, Inc.
Harvey Deitel
Deitel & Associates, Inc.
Traducción
Alfonso Vidal Romero Elizondo
Ingeniero en Sistemas Electrónicos
Instituto Tecnológico y de Estudios Superiores de Monterrey - Campus Monterrey
Revisión técnica
Sergio Fuenlabrada Velázquez
Edna Martha Miranda Chávez
Judith Sonck Ledezma
Mario Alberto Sesma Martínez
Mario Oviedo Galdeano
José Luis López Goytia
Departamento de Sistemas
Unidad Profesional Interdisciplinaria de Ingeniería y Ciencias Sociales
y Administrativas, Instituto Politécnico Nacional, México
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e
pf1f
pf20
pf21
pf22
pf23
pf24
pf25
pf26
pf27
pf28
pf29

Vista previa parcial del texto

¡Descarga Manejo de Archivos y Flujos en Java: Guía Detallada y más Guías, Proyectos, Investigaciones en PDF de Programación Java solo en Docsity!

TM

Paul Deitel

Deitel & Associates, Inc.

Harvey Deitel

Deitel & Associates, Inc.

Traducción

Alfonso Vidal Romero Elizondo

Ingeniero en Sistemas Electrónicos

Instituto Tecnológico y de Estudios Superiores de Monterrey - Campus Monterrey

Revisión técnica

Sergio Fuenlabrada Velázquez

Edna Martha Miranda Chávez

Judith Sonck Ledezma

Mario Alberto Sesma Martínez

Mario Oviedo Galdeano

José Luis López Goytia

Departamento de Sistemas

Unidad Profesional Interdisciplinaria de Ingeniería y Ciencias Sociales

y Administrativas, Instituto Politécnico Nacional, México

Archivos, flujos y serialización

de objetos

La conciencia … no aparece

a sí misma cortada en pequeños

pedazos. …Un “río” o un “flujo”

son las metáforas por las cuales se

describe con más naturalidad.

—William James

O b j e t i v o s

En este capítulo aprenderá:

■ A crear, leer, escribir y actualizar

archivos.

■ A obtener información de los

archivos y directorios mediante

las funciones de las API NIO.2.

■ A conocer las diferencias entre

los archivos de texto y los

archivos binarios.

■ A utilizar la clase Formatter

para enviar texto a un archivo.

■ A utilizar la clase Scanner para

recibir texto de un archivo.

■ A escribir y leer objetos de un

archivo mediante el uso de

la serialización de objetos

y la interfaz Serializable,

además de las clases

ObjectInputStream

y ObjectOutputStream.

■ A utilizar un cuadro de diálogo

JFileChooser para que los

usuarios puedan seleccionar

archivos o directorios en un

disco.

646 Capítulo 15 Archivos, flujos y serialización de objetos

archivo ocurre como una excepción. En otros casos, la indicación es un valor de retorno de un método

invocado en un objeto procesador de flujos.

Flujos basados en bytes y basados en caracteres

Los flujos de archivos se pueden utilizar para la entrada y salida de datos, ya sea como bytes o como

caracteres.

  • Los flujos basados en bytes reciben y envían datos en su formato binario ; un char es de dos bytes,

un int es de cuatro bytes, un double es de ocho bytes, etcétera.

  • Los flujos basados en caracteres reciben y envían datos como una secuencia de caracteres en la que

cada carácter es de dos bytes; el número de bytes para un valor dado depende del número de ca-

racteres en ese valor. Por ejemplo, el valor 2000000000 requiere 20 bytes (10 caracteres a 2 bytes

por carácter), pero el valor 7 requiere sólo dos bytes (1 carácter a dos bytes por carácter).

Los archivos que se crean usando flujos basados en bytes se conocen como archivos binarios , mientras

que los archivos que se crean usando flujos basados en caracteres se conocen como archivos de texto.

Los archivos de texto se pueden leer con editores de texto, mientras que los archivos binarios se leen

mediante programas que comprenden el contenido específico del archivo y su orden. Un valor numéri-

co en un archivo binario se puede utilizar en cálculos, mientras que en una cadena de texto, por ejemplo,

el carácter 5 es simplemente un carácter que puede utilizarse como en “Sarah Miller tiene 15 años

de edad”.

Flujos estándar de entrada, salida y error

Un programa de Java abre un archivo creando un objeto y asociándole un flujo de bytes o de caracteres.

El constructor del objeto interactúa con el sistema operativo para abrir el archivo. Java también pue-

de asociar flujos con distintos dispositivos. Cuando un programa de Java empieza a ejecutarse crea

tres objetos flujo que se asocian con dispositivos: System.in, System.out y System.err. Por lo general,

System.in (el objeto flujo estándar de entrada) permite a un programa recibir bytes desde el teclado. El

objeto System.out (el objeto flujo estándar de salida) generalmente permite a un programa mostrar

datos en la pantalla. El objeto System.err (el objeto flujo estándar de error) normalmente permite a

un programa mostrar en la pantalla mensajes de error basados en caracteres. Cada uno de estos flujos

puede redirigirse. Para System.in, esta capacidad permite al programa leer bytes desde un origen dis-

tinto. Para System.out y System.err esta capacidad permite que la salida se envíe a una ubicación

distinta, como un archivo en disco. La clase System proporciona los métodos setIn , setOut y setErr

para redirigir los flujos estándar de entrada, salida y de error, respectivamente.

Los paquetes java.io y java.nio

Los programas de Java realizan el procesamiento de archivos mediante las clases e interfaces del paquete

java.io y los subpaquetes de java.nio , que son las nuevas API de E/S de Java que se introdujeron por

primera vez en Java SE 6 y que se han ido mejorando desde entonces. Hay también otros paquetes en las

API de Java que contienen clases e interfaces basadas en las de los paquetes java.io y java.nio.

Fig. 15.1  La manera en que Java ve a un archivo de n bytes.

0 1 2 3 4 5 6 7 8 9 ... ...

n-

marcador de fin de archivo

15.3 Uso de clases e interfaces NIO para obtener información de archivos y directorios 647

Las operaciones de entrada y salida basadas en caracteres se pueden llevar a cabo con las clases

Scanner y Formatter , como veremos en la sección 15.4. Hemos usado la clase Scanner con mucha

frecuencia para recibir datos del teclado, pero esta clase también puede leer datos desde un archivo.

La clase Formatter permite mostrar datos con formato a cualquier flujo basado en texto, en forma si-

milar al método System.out.printf. En el apéndice I se presentan los detalles acerca de la salida con

formato mediante printf. Todas estas características se pueden utilizar también para dar formato a los

archivos de texto. En el capítulo 28 (en inglés, en el sitio web del libro) usaremos las clases de flujos para

implementar aplicaciones de redes.

Java SE 8 agrega otro tipo de flujo

En el capítulo 17, Lambdas y flujos de Java SE 8, presentaremos un nuevo tipo de flujo que se utiliza para

procesar colecciones de elementos (como arreglos y objetos ArrayList), en vez de los flujos de bytes que

veremos en los ejemplos de procesamiento de archivos de este capítulo.

15.3 Uso de clases e interfaces NIO para obtener información

de archivos y directorios

Las interfaces Path y DirectoryStream, junto con las clases Paths y Files (todas del paquete

java.nio.file) son útiles para recuperar información sobre los archivos y directorios en el disco:

  • La interfaz Path. Los objetos de las clases que implementan esta interfaz representan la ubicación

de un archivo o directorio. Los objetos Path no abren archivos ni proporcionan herramientas de

procesamiento de archivos.

  • La clase Paths. Proporciona métodos static que se usan para obtener un objeto Path, el cual

representa la ubicación de un archivo o directorio.

  • La clase Files. Proporciona métodos static para manipulaciones comunes de archivos y direc-

torios, como copiar archivos, crear y eliminar archivos y directorios, obtener información sobre

archivos y directorios, leer el contenido de archivos, obtener objetos que permitan manipular el

contenido de los archivos y directorios, y más.

  • La interfaz DirectoryStream. Los objetos de las clases que implementan esta interfaz permiten a

un programa iterar a través del contenido de un directorio.

Creación de objetos Path

Podrá usar el método static get de la clase Paths para convertir un objeto String, que representa la

ubicación de un archivo o directorio, en un objeto Path. Después podrá usar los métodos de la interfaz

Path y la clase Files para determinar información sobre el archivo o directorio especificado. A conti-

nuación hablaremos sobre varios de esos métodos. Para las listas completas de sus métodos, visite:

http://docs.oracle.com/javase/7/docs/api/java/nio/file/Path.html http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html

Comparación entre rutas absolutas y rutas relativas

La ruta de un archivo o directorio especifica su ubicación en el disco. La ruta incluye algunos o todos los

directorios que conducen a ese archivo o directorio. Una ruta absoluta contiene todos los directorios

—empezando con el directorio raíz — que conducen a un archivo o directorio específico. Cada archivo

o directorio en un disco duro específico tiene el mismo directorio raíz en su ruta. Una ruta relativa es

“relativa” al directorio actual; es decir, se trata de una ruta que está en función del directorio en el que

la aplicación empezó a ejecutarse.

15.3 Uso de clases e interfaces NIO para obtener información de archivos y directorios 649

El primer resultado de este programa demuestra un objeto Path para la carpeta que contiene los

ejemplos de este capítulo. El segundo resultado demuestra un objeto Path para el archivo de código fuente

de este ejemplo. En ambos casos especificamos una ruta absoluta.

1 // Fig. 15.2: InfoArchivosYDirectorios.java
2 // Clase File utilizada para obtener información sobre archivos y directorios.
3 import java.io.IOException;
4 import java.nio.file.DirectoryStream;
5 import java.nio.file.Files;
6 import java.nio.file.Path;
7 import java.nio.file.Paths;
8 import java.util.Scanner;
10 public class InfoArchivosYDirectorios
12 public static void main(String[] args) throws IOException
14 Scanner entrada = new Scanner(System.in);
16 System.out.println(“Escriba el nombre del archivo o directorio:”);
18 // crear objeto Path con base en la entrada del usuario
19 Path ruta = Paths.get(entrada.nextLine());
21 if (Files.exists(ruta)) // si la ruta existe, mostrar en pantalla

información sobre ella

23 // mostrar información de archivo (o directorio)
24 System.out.printf(“%n%s existe%n”, ruta.getFileName());
25 System.out.printf(“%s un directorio%n”,
26 Files.isDirectory(ruta)? “Es” : “No es”);
27 System.out.printf(“%s una ruta absoluta%n”,
28 ruta.isAbsolute()? “Es” : “No es”);
29 System.out.printf(“Fecha de ultima modificacion: %s%n”,
30 Files.getLastModifiedTime(ruta));
31 System.out.printf(“Tamanio: %s%n”, Files.size(ruta));
32 System.out.printf(“Ruta: %s%n”, ruta);
33 System.out.printf(“Ruta absoluta: %s%n”, ruta.toAbsolutePath());
35 if (Files.isDirectory(ruta)) // imprime en pantalla el listado del

directorio

37 System.out.printf(“%nContenido del directorio:%n”);
39 // objeto para iterar a través del contenido de un directorio
40 DirectoryStream flujoDirectorio =
41 Files.newDirectoryStream(ruta);
43 for (Path p : flujoDirectorio)
44 System.out.println(r);
47 else // no es archivo o directorio, imprimir en pantalla mensaje de error

Fig. 15.2  Uso de la clase File para obtener información sobre archivos y directorios (parte 1 de 2).

650 Capítulo 15 Archivos, flujos y serialización de objetos

Caracteres separadores

Un carácter separador se utiliza para separar directorios y archivos en la ruta. En un equipo Windows,

el carácter separador es la barra diagonal inversa (). En un sistema Linux o Mac OS X, el carácter separa-

dor es la barra diagonal (/). Java procesa ambos caracteres en forma idéntica en el nombre de una ruta.

Por ejemplo, si deseamos utilizar la ruta

c:\Archivos de programa\Java\jdk1.6.0_11\demo/jfc

que emplea a cada uno de los caracteres separadores, Java de todas formas procesa la ruta en forma

apropiada.

49 System.out.printf(“%s no existe%n”, ruta);
51 } // fin de main
52 } // fin de la clase InfoArchivosYDirectorios

Escriba el nombre del archivo o directorio: e:\ejemplos\cap

cap15 existe Es un directorio Es una ruta absoluta Fecha de ultima modificacion: 2013-11-08T19:50:00.838256Z Tamanio: 4096 Ruta: c:\ejemplos\cap Ruta absoluta: c:\ejemplos\cap

Contenido del directorio: C:\ejemplos\cap15\fig15_ C:\ejemplos\cap15\fig15_12_ C:\ejemplos\cap15\AppsSerializacion C:\ejemplos\cap15\AppsArchivosTexto

Escriba el nombre del archivo o directorio: c:\ejemplos\cap15\fig15_02\InfoArchivosYDirectorios.java

InfoArchivosYDirectorios.java existe No es un directorio Es una ruta absoluta Fecha de ultima modificacion: 2016-05-03T18:26:32Z Tamanio: 3151 Ruta: c:\ejemplos_codigo\cap15\fig15_02\InfoArchivosYDirectorios.java Ruta absoluta: c:\ejemplos_codigo\cap15\fig15_02\InfoArchivosYDirectorios.java

Fig. 15.2  Uso de la clase File para obtener información sobre archivos y directorios (parte 2 de 2).

Tip para prevenir errores 15.

Una vez que se confirma que existe un objeto Path , aún es posible que los métodos demostrados en la

figura 15.2 lancen excepciones IOException. Por ejemplo, el archivo o directorio representado por

el objeto Path podría eliminarse del sistema después de la llamada al método exists de Files y antes

de que se ejecuten las otras instrucciones en las líneas 24 a 45. Los programas de procesamiento de

archivos y directorios para uso industrial requieren de un manejo exhaustivo de las excepciones para

recuperarse de dichas posibilidades.

652 Capítulo 15 Archivos, flujos y serialización de objetos

1 // Fig. 15.3: CrearArchivoTexto.java
2 // Escribir datos en un archivo de texto secuencial mediante la clase Formatter.
3 import java.io.FileNotFoundException;
4 import java.lang.SecurityException;
5 import java.util.Formatter;
6 import java.util.FormatterClosedException;
7 import java.util.NoSuchElementException;
8 import java.util.Scanner;
10 public class CrearArchivoTexto
12 private static Formatter salida; // envía texto a un archivo
14 public static void main(String[] args)
16 abrirArchivo();
17 agregarRegistros();
18 cerrarArchivo();
21 // abre el archivo clientes.txt
22 public static void abrirArchivo()
24 try
26 salida = new Formatter(“clientes.txt”); // abre el archivo
28 catch (SecurityException securityException)
30 System.err.println(“Permiso de escritura denegado. Terminando.”);
31 System.exit(1); // termina el programa
33 catch (FileNotFoundException fileNotFoundException)
35 System.err.println(“Error al abrir el archivo. Terminando.”);
36 System.exit(1); // termina el programa
40 // agrega registros al archivo
41 public static void agregarRegistros()
43 Scanner entrada = new Scanner(System.in);
44 System.out.printf(“%s%n%s%n? “,
45 “Escriba numero de cuenta, nombre, apellido y saldo.”,
46 “Para terminar la entrada, escriba el indicador de fin de archivo.”);
48 while (entrada.hasNext()) // itera hasta encontrar el indicador de fin de

archivo

50 try

Fig. 15.3  Escritura de datos en un archivo de texto secuencial mediante la clase Formatter (parte 1 de 2).

15.4 Archivos de texto de acceso secuencial 653

52 // escribe el nuevo registro en el archivo; asume una entrada válida
53 salida.format(“%d %s %s %.2f%n”, entrada.nextInt(),
54 entrada.next(), entrada.next(), entrada.nextDouble());
56 catch (FormatterClosedException formatterClosedException)
58 System.err.println(“Error al escribir en el archivo. Terminando.”);
59 break;
61 catch (NoSuchElementException elementException)
63 System.err.println(“Entrada invalida. Intente de nuevo.”);
64 entrada.nextLine(); // descarta la entrada para que el usuario

intente de nuevo

67 System.out.print(“? “);
68 } // fin de while
69 } // fin del método agregarRegistros
71 // cierra el archivo
72 public static void cerrarArchivo()
74 if (salida != null)
75 salida.close();
77 } // fin de la clase CrearArchivoTexto

Escriba numero de cuenta, nombre, apellido y saldo. Para terminar la entrada, escriba el indicador de fin de archivo. ? 100 Bob Blue 24. ? 200 Steve Green -345. ? 300 Pam White 0. ? 400 Sam Red -42. ? 500 Sue Yellow 224. ? ^Z

Fig. 15.3  Escritura de datos en un archivo de texto secuencial mediante la clase Formatter (parte 2 de 2).

En las líneas 28 a 32 se maneja la excepción tipo SecurityException , que ocurre si el usuario no tiene

permiso para escribir datos en el archivo. En las líneas 33 a 37 se maneja la excepción tipo FileNotFound-

Exception que ocurre si el archivo no existe y no se puede crear uno nuevo. Esta excepción también puede

ocurrir si hay un error al abrir el archivo. En ambos manejadores de excepciones podemos llamar al méto-

do static System.exit y pasarle el valor 1. Este método termina la aplicación. Un argumento de 0 para

el método exit indica la terminación exitosa del programa. Un valor distinto de cero, como el 1 en este

ejemplo, por lo general indica que ocurrió un error. Este valor se pasa a la ventana de comandos en la que

se ejecutó el programa. El argumento es útil si el programa se ejecuta desde un archivo de procesamiento

por lotes en los sistemas Windows, o una secuencia de comandos de shell en sistemas UNIX/Linux/Mac

OS X. Los archivos de procesamiento por lotes y las secuencias de comandos de shell ofrecen una manera

conveniente de ejecutar varios programas en secuencia. Cuando termina el primer programa, el siguiente

programa empieza su ejecución. Se puede usar el argumento para el método exit en un archivo de proce-

samiento por lotes o en una secuencia de comandos de shell, para determinar si deben ejecutarse otros

programas. Para obtener más información sobre los archivos de procesamiento por lotes o las secuencias de

comandos de shell, consulte la documentación de su sistema operativo.

15.4 Archivos de texto de acceso secuencial 655

15.4.2 Cómo leer datos de un archivo de texto de acceso secuencial

Los datos se almacenan en archivos para poder procesarlos según sea necesario. En la sección 15.4.1 demos-

tramos cómo crear un archivo para acceso secuencial. Esta sección muestra cómo leer los datos en forma

secuencial desde un archivo de texto. Demostraremos cómo puede utilizarse la clase Scanner para recibir

datos de un archivo, en vez del teclado. La aplicación (figura 15.6) lee registros del archivo “clientes.txt”

creado por la aplicación de la sección 15.4.1 y muestra el contenido de los registros. En la línea 13 se declara

un objeto Scanner, que se utilizará para obtener los datos de entrada del archivo.

Fig. 15.5  Datos de ejemplo para el programa de la figura 15.3.

Datos de ejemplo

100 Bob Blue 24.

200 Steve Green -345.

300 Pam White 0.

400 Sam Red -42.

500 Sue Yellow 224.

Fig. 15.6  Lectura de un archivo secuencial mediante un objeto Scanner (parte 1 de 2).

1 // Fig. 15.6: LeerArchivoTexto.java
2 // Este programa lee un archivo de texto y muestra cada registro.
3 import java.io.IOException;
4 import java.lang.IllegalStateException;
5 import java.nio.file.Files;
6 import java.nio.file.Path;
7 import java.nio.file.Paths;
8 import java.util.NoSuchElementException;
9 import java.util.Scanner;
11 public class LeerArchivoTexto
13 private static Scanner entrada;
15 public static void main(String[] args)
17 abrirArchivo();
18 leerRegistros();
19 cerrarArchivo();
22 // abre el archivo clientes.txt
23 public static void abrirArchivo()
25 try
27 entrada = new Scanner(Paths.get(“clientes.txt”));

656 Capítulo 15 Archivos, flujos y serialización de objetos

El método abrirArchivo (líneas 23 a 34) abre el archivo en modo de lectura, creando una instancia

de un objeto Scanner en la línea 27. Pasamos un objeto Path al constructor, el cual especifica que el objeto

Scanner leerá datos del archivo “clientes.txt” ubicado en el directorio desde el que se ejecuta la aplica-

ción. Si no puede encontrarse el archivo, ocurre una excepción tipo IOException. La excepción se maneja

en las líneas 29 a 33.

Fig. 15.6  Lectura de un archivo secuencial mediante un objeto Scanner (parte 2 de 2).

29 catch (IOException ioException)
31 System.err.println(“Error al abrir el archivo. Terminando.”);
32 System.exit(1);
36 // lee registro del archivo
37 public static void leerRegistros()
39 System.out.printf(“%-10s%-12s%-12s%10s%n”, “Cuenta”,
40 “Primer nombre”, “Apellido paterno”, “Saldo”);
42 try
44 while (entrada.hasNext) // mientras haya más qué leer
46 // muestra el contenido del registro
47 System.out.printf(“%-10d%-12s%-12s%10.2f%n”, entrada.nextInt(),
48 entrada.next(), entrada.next(), entrada.nextDouble());
51 catch (NoSuchElementException elementException)
53 System.err.println(“El archivo no esta bien formado. Terminando.”);
55 catch (IllegalStateException stateException)
57 System.err.println(“Error al leer del archivo. Terminando.”);
59 } // fin del método leerRegistros
61 // cierra el archivo y termina la aplicación
62 public static void cerrarArchivo()
64 if (entrada != null)
65 entrada.close();
67 } // fin de la clase LeerArchivoTexto

Cuenta Primer nombre Apellido paterno Saldo 100 Bob Blue 24. 200 Steve Green -345. 300 Pam White 0. 400 Sam Red -42. 500 Sue Yellow 224.

658 Capítulo 15 Archivos, flujos y serialización de objetos

La clase ConsultaCredito

La figura 15.18 contiene la funcionalidad para el programa de consulta de crédito. Este programa muestra

un menú de texto y permite al gerente de créditos introducir una de tres opciones para obtener información

sobre un crédito:

  • La opción 1 (SALDO_CERO) muestra las cuentas con saldos de cero.
  • La opción 2 (SALDO_CREDITO) muestra las cuentas con saldos con crédito.
  • La opción 3 (SALDO_DEBITO) muestra las cuentas con saldos con débito.
  • La opción 4 (FIN) termina la ejecución del programa.
14 // constructor
15 private OpcionMenu(int valor)
17 this.valor = valor;
19 } // fin del tipo enum OpcionMenu

Fig. 15.7  Enumeración para las opciones del menú del programa de consulta de crédito (parte 2 de 2).

Fig. 15.8  Programa de consulta de crédito (parte 1 de 4).

1 // Fig. 15.8: ConsultaCredito.java
2 // Este programa lee un archivo secuencialmente y muestra su
3 // contenido con base en el tipo de cuenta que solicita el usuario
4 // (saldo con crédito, saldo con débito o saldo de cero).
5 import java.io.IOException;
6 import java.lang.IllegalStateException;
7 import java.nio.file.Paths;
8 import java.util.NoSuchElementException;
9 import java.util.Scanner;
11 public class ConsultaCredito
13 private final static OpcionMenu[] opciones = OpcionMenu.values();
15 public static void main(String[] args)
17 // obtiene la solicitud del usuario (saldo de cero, con crédito o con débito)
18 OpcionMenu tipoCuenta = obtenerSolicitud();
20 while (tipoCuenta != OpcionMenu.FIN)
22 switch (tipoCuenta)
24 case SALDO_CERO:
25 System.out.printf(“%nCuentas con saldos de cero:%n”);
26 break;
27 case SALDO_CREDITO:
28 System.out.printf(“%nCuentas con saldos con credito:%n”);
29 break;

15.4 Archivos de texto de acceso secuencial 659

Fig. 15.8  Programa de consulta de crédito (parte 2 de 4).

30 case SALDO_DEBITO:
31 System.out.printf(“%nCuentas con saldos con debito:%n”);
32 break;
35 leerRegistros(tipoCuenta);
36 tipoCuenta = obtenerSolicitud(); // obtiene la solicitud del usuario
40 // obtiene la solicitud del usuario
41 private static OpcionMenu obtenerSolicitud()
43 int solicitud = 4;
45 // muestra opciones de solicitud
46 System.out.printf(“%nEscriba solicitud%n%s%n%s%n%s%n%s%n”,
47 “ 1 - Lista de cuentas con saldos de cero”,
48 “ 2 - Lista de cuentas con saldos con credito”,
49 “ 3 - Lista de cuentas con saldos con debito”,
50 “ 4 - Terminar programa”);
52 try
54 Scanner entrada = new Scanner(System.in);
56 do // recibe solicitud del usuario
58 System.out.printf(“%n? “);
59 solicitud = entrada.nextInt();
60 } while ((solicitud < 1) || (solicitud > 4));
62 catch (NoSuchElementException noSuchElementException)
64 System.err.println(“Entrada invalida. Terminando.”);
67 return opciones[solicitud - 1]; // devuelve valor de enum para la opción
70 // lee los registros del archivo y muestra sólo los registros del tipo apropiado
71 private static void leerRegistros(OpcionMenu tipoCuenta)
73 // abre el archivo y procesa el contenido
74 try (Scanner entrada = new Scanner(Paths.get(“clientes.txt”)))
76 while (entrada.hasNext()) // más datos a leer
78 int numeroCuenta = entrada.nextInt();
79 String primerNombre = entrada.next();
80 String apellidoPaterno = entrada.next();
81 double saldo = entrada.nextDouble();

15.4 Archivos de texto de acceso secuencial 661

Para recolectar la información de los registros, se lee todo el archivo completo y se determina si

cada uno de los registros cumple o no con los criterios para el tipo de cuenta seleccionado. En la línea 18

en main se hace una llamada al método obtenerSolicitud (líneas 41 a 68) para mostrar las opciones

del menú, se traduce el número introducido por el usuario en un objeto OpcionMenu y se almacena el

resultado en la variable OpcionMenu llamada tipoCuenta. En las líneas 20 a 37 se itera hasta que el usua-

rio especifique que el programa debe terminar. En las líneas 22 a 33 se muestra un encabezado para

imprimir el conjunto actual de registros en la pantalla. En la línea 35 se hace una llamada al método

leerRegistros (líneas 71 a 97), el cual itera a través del archivo y lee todos los registros.

El método leerRegistros usa una instrucción try con recursos (que se presentó en la sección

11.12) para crear un objeto Scanner que abre el archivo en modo de lectura (línea 74). Recuerde que

try con recursos cierra sus recursos cuando el bloque try termina con éxito o debido a una excepción.

Cada vez que se haga una llamada a leerRegistros, el archivo se abrirá en modo de lectura con un

nuevo objeto Scanner para que podamos leer de nuevo desde el principio del archivo. En las líneas 78 a

81 se lee un registro. En la línea 84 se hace una llamada al método debeMostrar (líneas 100 a 111), para

determinar si el registro actual cumple con el tipo de cuenta solicitado. Si debeMostrar devuelve true,

el programa muestra la información de la cuenta. Al llegar al marcador de fin de archivo , el ciclo termina

y la instrucción try con recursos cierra el objeto Scanner junto con el archivo. Una vez que se hayan

leído todos los registros, el control regresa al método main y se hace otra vez una llamada al método

obtenerSolicitud (línea 36) para obtener la siguiente opción de menú del usuario.

15.4.4 Actualización de archivos de acceso secuencial

En muchos archivos secuenciales los datos no se pueden modificar sin el riesgo de destruir otros datos en

el archivo. Por ejemplo, si el nombre “White” tuviera que cambiarse a “Worthington”, el nombre anterior

no podría simplemente sobrescribirse ya que el nuevo nombre requiere más espacio. El registro para White

se escribió en el archivo como

300 Pam White 0.

Fig. 15.8  Programa de consulta de crédito (parte 4 de 4).

Escriba solicitud 1 - Lista de cuentas con saldos de cero 2 - Lista de cuentas con saldos con credito 3 - Lista de cuentas con saldos con debito 4 - Terminar programa

? 3

Cuentas con saldos con debito: 100 Bob Blue 24. 500 Sue Yellow 224.

Escriba solicitud 1 - Lista de cuentas con saldos de cero 2 - Lista de cuentas con saldos con credito 3 - Lista de cuentas con saldos con debito 4 - Terminar programa

? 4

662 Capítulo 15 Archivos, flujos y serialización de objetos

Si el registro se sobrescribe empezando en la misma ubicación en el archivo que utiliza el nuevo nombre, el

registro será

300 Pam Worthington 0.

El nuevo registro es más extenso (tiene más caracteres) que el registro original. “Worthington” sobres-

cribiría el valor “0.00” en el registro actual y los caracteres más allá de la segunda “o” en “Worthington”

sobrescribirán el principio del siguiente registro secuencial en el archivo. El problema aquí es que los

campos en un archivo de texto (y por ende, los registros) pueden variar en tamaño. Por ejemplo, 7, 14,

-117, 2074 y 27383 son todos valores int almacenados en el mismo número de bytes (4) interna-

mente, pero son campos con distintos tamaños cuando se escriben en un archivo como texto. Por lo

tanto, los registros en un archivo de acceso secuencial comúnmente no se actualizan por partes. En vez

de ello, se sobrescribe todo el archivo. Para realizar el cambio anterior, los registros que se encuen-

tran antes de 300 Pam White 0.00 se copian a un nuevo archivo, luego se escribe el nuevo registro (que

puede tener un tamaño distinto al que está sustituyendo) y se copian los registros después de 300 Pam

White 0.00 al nuevo archivo. No es muy conveniente actualizar sólo un registro, pero resulta razonable

si una porción sustancial de los registros necesita actualización.

15.5 Serialización de objetos

En la sección 15.4 demostramos cómo escribir los campos individuales de un registro en un archivo

como texto y cómo leer esos campos desde un archivo. Cuando los datos se enviaban al disco, se perdía

cierta información como el tipo de cada valor. Por ejemplo, si se lee el valor “ 3 ” de un archivo, no hay

forma de saber si el valor proviene de un int, un String o un double. En un disco sólo tenemos los

datos, no la información sobre los tipos.

Algunas veces es necesario leer o escribir un objeto en un archivo o a través de una conexión de

red. Java cuenta con la serialización de objetos para estos fines. Un objeto serializado es un objeto

que se representa como una secuencia de bytes, la cual incluye los datos del objeto, así como informa-

ción acerca del tipo del objeto y los tipos de los datos almacenados en el mismo. Una vez que se escribe

un objeto serializado en un archivo, se puede leer desde ese archivo y deserializarse ; es decir, la infor-

mación del tipo y los bytes que representan al objeto y sus datos se puede utilizar para recrear el objeto

en memoria.

Las clases ObjectInputStream y ObjectOutputStream

Las clases ObjectInputStream y ObjectOutputStream (paquete java.io), que implementan respecti-

vamente a las interfaces ObjectInput y ObjectOutput , permiten leer y escribir objetos completos desde

o en un flujo (posiblemente un archivo). Para utilizar la serialización con los archivos, inicializamos los

objetos ObjectInputStream y ObjectOutputStream con objetos flujo que pueden leer y escribir infor-

mación desde y hacia los archivos. La acción de inicializar de esta forma objetos flujo con otros objetos

flujo se conoce algunas veces como envoltura , ya que el nuevo objeto flujo que se va a crear “envuelve”

al objeto flujo especificado como un argumento del constructor.

Las clases ObjectInputStream y ObjectOutputStream simplemente leen y escriben la representa-

ción basada en bytes de los objetos; no saben de dónde leer los bytes o en dónde escribirlos. El objeto

flujo que pasamos al constructor de ObjectInputStream recibe la representación basada en bytes del

objeto que el ObjectOutputStream produce, y escribe los bytes en el destino especificado (por ejemplo,

un archivo o una conexión en red).