- OFIR GIZEH VAZQUEZ PEREZ
- PERLA GUADALUPE HERNANDEZ ARIAS
- LAURA SANCHEZ MORALES
lunes
domingo
Introducción
Conceptos Básicos sobre Hilos
Un proceso es un programa ejecutándose dentro de su propio espacio de direcciones. Java es un sistema multiproceso, esto significa que soporta varios procesos corriendo a la vez dentro de sus propios espacios de direcciones. Un hilo es una secuencia de código en ejecución dentro del contexto de un proceso.
Los hilos no pueden ejecutarse ellos solos; requieren la supervisión de un proceso padre para correr. Dentro de cada proceso hay varios hilos ejecutándose. Por ejemplo, Word puede tener un hilo en background chequeando automáticamente la gramática de lo que estoy escribiendo, mientras otro hilo puede estar salvando automáticamente los cambios del documento en el que estoy trabajando.
Los hilos a menudo son conocidos o llamados procesos ligeros. Un hilo, en efecto, es muy similar a un proceso pero con la diferencia de que un hilo siempre corre dentro del contexto de otro programa. Por el contrario, los procesos mantienen su propio espacio de direcciones y entorno de operaciones. Los hilos dependen de un programa padre en lo que se refiere a recursos de ejecución. La siguiente figura muestra le relación entre hilos y procesos.
ESTADOS DE UN HILO
Igual que los procesos un solo hilo de control, los hilos pueden encontrarse en uno de los siguientes estados:
Nuevo. El hilo ha sido creado pero aún no ha sido activado. Cuando se active pasará al estado preparado.
Preparado. El hilo está activo y está a la espera de que le sea asignada la UCP.
En ejecución. El hilo está activo y le ha sido asignada la UCP (sólo los hilos activos, preparados, pueden ser ejecutados).
Bloqueado. El hilo espera que otro elimine el bloqueo. Un hilo bloqueado puede estar:
Dormido. El hilo está bloqueado durante una cantidad de tiempo determinada (por ejemplo, tres segundos), después de la cual despertará y pasará al estado preparado.
Esperando. El hilo está esperando a que ocurra alguna cosa: una condición, una operación de E/S o adquirir la propiedad de un objeto de sincronismo. Cuando ocurra, pasará al estado preparado.
Muerto. El hilo ha finalizado (está muerto) pero todavía no ha sido recogido por su padre. Los hilos muertos no pueden alcanzar ningún otro estado.
Obsérvese en la figura anterior que no se muestra los estados nuevo y muerto ya que no son estados de transición durante la vida del hilo; esto es, no se puede transitar al estado nuevo ni desde el estado muerto.
La transición entre estados está controlada por el planificador: parte del núcleo del sistema operativo encargada de que todos los hilos que esperan ejecutarse tengan su oportunidad. Si un hilo en ejecución no puede continuar, pasará al estado bloqueado; o también, si puede continuar y el planificador decide que ya ha sido ejecutado el tiempo suficiente, pasará a preparado cuando se dé el evento por el que espera; por ejemplo, puede estar esperando a que otro hilo elimine el bloqueo, o bien si está dormido, esperará a que pase el tiempo por el que fue enviado a este estado para ser activado; y si está preparado, pasará a ejecución cuando el planificador lo decida porque los demás hilos ya han tenido su parte de tiempo de UCP.
CUANDO SE DEBE CREAR UN HILO
Cada vez que se crea un proceso, el sistema operativo crea un hilo primario. Para muchos procesos éste es el único hilo necesario. Sin embargo, un proceso puede crear otros hilos para ayudarse en su trabajo, utilizando al máximo la UCP al máximo posible. Por ejemplo, supongamos el diseño de una aplicación procesador de texto. ¿Seria acertado crear un hilo separado para manipular cualquier tarea de impresión? Esto permitiría al usuario continuar utilizando la aplicación mientras se está imprimiendo el documento. En cambio, ¿Qué sucederá si los datos del documento cambian mientras se imprime? Éste es un problema que habría que resolver, quizás creando un fichero temporal que contenga los datos a imprimir.
PROGRAMAR CON HILOS
La mayoría del soporte que Java proporciona para trabajar con hilos reside en la clase Thread del paquete java.lang, aunque también la clase Object, la interfaz Runnable, la interfaz Thread.UncaughtExceptionHandler y las clases ThreadGroup y Threadlocal del mismo paquete, así como la maquina virtual, proporciona algún tipo de soporte.
GRUPO DE HILOS
Cada hilo Java es un miembro de un grupo de hilos. Este grupo puede ser el predefinido por Java o uno especificado explícitamente. Los grupos de hilos proporcionan un mecanismo para agrupar varios hilos en un único objeto con el fin de poder manipularlos todos de una vez; por ejemplo, poder interrumpir un grupo de hilos invocando una sola vez al método interrupt. A su vez, un grupo de hilos también puede pertenecer a otro grupo, formando una estructura en árbol. Desde el punto de vista de esta estructura, un hilo sólo tiene acceso a la información acerca de su grupo, no a la de su grupo padre o de cualquier otro grupo.
Java proporciona soporte para trabajar con grupos de hilos a través de la clase ThreadGroup del paquete lang.
Grupo Predefinido
Cuando creamos un hilo sin especificar su grupo en el constructor, Java lo coloca en el mismo grupo (grupo actual) del hilo bajo el cual se crea (hilo actual).
Por ejemplo, la siguiente aplicación obtiene una referencia al grupo actual (grupo predefinido) al cual pertenece el hilo actual (en este caso el hilo primario) y almacena en consumidores.
Después, cada hilo consumidor que es creado es añadido al grupo actual que hemos denominado consumidores.
Finalmente, más adelante, se envía al grupo actual el mensaje list con el objetivo de escribir información acerca del grupo de hilos.
public class Test
{
public static void main (String [] args)
{
TreadGroup consumidores=
Tread.currentThread().getThreadGroup();
CMensaje mensaje = new CMensaje ();
Productor productor1=new Productor (mensaje, consumidores,
“consumidor1”);
Consumidor consumidor2=new Consumidor (mensaje, consumidores,
“consumidor2”);
consumidores.list();
//…
}
}
¿Cómo se añaden los hilos a un grupo? Pues utilizando alguno de los constructores que la clase Thread proporciona para ello. Por ejemplo:
Thread(ThreadGroup grupo, String nombreHilo)
Siguiendo con el ejemplo anterior, vemos que cuando se invocó al constructor Consumidor se pasaron tres argumentos: un objeto CMensaje, al grupo de hilos y el nombre del hilo que se desea añadir al grupo. Según esto, el constructor de esta clase será como se indica a continuación:
public class Consumidor extends Thread
{
prívate CMensaje mensaje; //mensaje a mostrar
public Consumidor (CMensaje msj, ThreadGroup grupo, String nombre)
{
super(grupo, nombre);
Mensaje = msj;
}
public void run()
{
//…
}
}
Se puede observar que el constructor de la clase Consumidor invoca al constructor de su clase base (Thread) pasándole como argumento el grupo al cual se quiere añadir el hilo, el cual está referenciado por this, y el nombre del hilo.
Grupo Explícito
Para añadir un hilo a un determinado grupo primero creamos el grupo y después procederemos de la misma forma explicada en el apartado anterior. Por ejemplo, si en el ejemplo anterior en lugar de utilizar el grupo predefinido por Java quisiéramos definir explícitamente un grupo referenciado por la variable consumidores y denominado también consumidores, la primera línea del método main la sustituiríamos por la sombreado en el código mostrado a continuación:
public class Test
{
public static void main (String [] args)
{
ThreadGroup consumidores =new ThreadGroup (“consumidores”);
//…
}
}
Fig. 14.4: DemostracionFile.java
import java.io.File;
public class DemostracionFile
{
// muestra información acerca del archivo especificado por el usuario
public void analizarRuta( String ruta )
{
// crea un objeto File con base en la entrada del usuario
File nombre = new File( ruta );
if ( nombre.exists() ) // si existe el nombre, muestra información sobre él
{
// muestra información del archivo (o directorio)
System.out.printf(
"%s%s\n%s\n%s\n%s\n%s%s\n%s%s\n%s%s\n%s%s\n%s%s",
nombre.getName(), " existe",
( nombre.isFile() ? "es un archivo" : "no es un archivo" ),
( nombre.isDirectory() ? "es un directorio" :
"no es un directorio" ),
( nombre.isAbsolute() ? "es ruta absoluta" :
"no es ruta absoluta" ), "Ultima modificacion: ",
nombre.lastModified(), "Tamanio: ", nombre.length(),
"Ruta: ", nombre.getPath(), "Ruta absoluta: ",
nombre.getAbsolutePath(), "Padre: ", nombre.getParent() );
if ( nombre.isDirectory() ) // muestra el listado del directorio
{
String directorio[] = nombre.list();
System.out.println( "\n\nContenido del directorio:\n" );
for ( String nombreDirectorio : directorio )
System.out.printf( "%s\n", nombreDirectorio );
} // fin de else
} // fin de if exterior
else // no es archivo o directorio, muestra mensaje de error
{
System.out.printf( "%s %s", ruta, "no existe." );
} // fin de else
} // fin del método analizarRuta
} // fin de la clase DemostracionFile
Fig. 14.5: PruebaDemostracionFile.java
import java.util.Scanner;
public class PruebaDemostracionFile
{
public static void main( String args[] )
{
Scanner entrada = new Scanner( System.in );
DemostracionFile aplicacion = new DemostracionFile();
System.out.print( "Escriba aqui el nombre del archivo o directorio: " );
aplicacion.analizarRuta( entrada.nextLine() );
} // fin de main
} // fin de la clase PruebaDemostracionFile
Fig. 14.5: PruebaDemostracionFile.java
import java.util.Scanner;
import java.io.File;
import java.net.URI;
public class Prueba
{
public static void main( String args[] )
{
try
{
File testFile = new File( "C:\\books\\2004\\sjhtp7e\\frame\\jhtp7_14_Files.fm" );
System.out.println( testFile.toURI().toString() );
}
catch ( Exception exception )
{
System.out.println( "exception" );
}
} // end main
} // end class Prueba
Fig. 14.5: RegistroCuenta.java
{
private int cuenta;
private String primerNombre;
private String apellidoPaterno;
private double saldo;
// el constructor sin argumentos llama a otro constructor con valores predeterminados
public RegistroCuenta()
{
this( 0, "", "", 0.0 ); // llama al constructor con cuatro argumentos
} // fin del constructor de RegistroCuenta sin argumentos
// inicializa un registro
public RegistroCuenta( int cta, String nombre, String apellido, double sal )
{
establecerCuenta( cta );
establecerPrimerNombre( nombre );
establecerApellidoPaterno( apellido );
establecerSaldo( sal );
} // fin del constructor de RegistroCuenta con cuatro argumentos
// establece el número de cuenta
public void establecerCuenta( int cta )
{
cuenta = cta;
} // fin del método establecerCuenta
// obtiene el número de cuenta
public int obtenerCuenta()
{
return cuenta;
} // fin del método obtenerCuenta
// establece el primer nombre
public void establecerPrimerNombre( String nombre )
{
primerNombre = nombre;
} // fin del método establecerPrimerNombre
// obtiene el primer nombre
public String obtenerPrimerNombre()
{
return primerNombre;
} // fin del método obtenerPrimerNombre
// establece el apellido paterno
public void establecerApellidoPaterno( String apellido )
{
apellidoPaterno = apellido;
} // fin del método establecerApellidoPaterno
// obtiene el apellido paterno
public String obtenerApellidoPaterno()
{
return apellidoPaterno;
} // fin del método obtenerApellidoPaterno
// establece el saldo
public void establecerSaldo( double sal )
{
saldo = sal;
} // fin del método establecerSaldo
// obtiene el saldo
public double obtenerSaldo()
{
return saldo;
} // fin del método obtenerSaldo
} // fin de la clase RegistroCuenta
Fig. 14.7: CrearArchivoTexto.java
import java.io.FileNotFoundException;
import java.lang.SecurityException;
import java.util.Formatter;
import java.util.FormatterClosedException;
import java.util.NoSuchElementException;
import java.util.Scanner;
import com.deitel.jhtp7.cap14.RegistroCuenta;
public class CrearArchivoTexto
{
private Formatter salida; // objeto usado para enviar texto al archivo
// permite al usuario abrir el archivo
public void abrirArchivo()
{
try
{
salida = new Formatter( "clientes.txt" );
} // fin de try
catch ( SecurityException securityException )
{
System.err.println(
"No tiene acceso de escritura a este archivo." );
System.exit( 1 );
} // fin de catch
catch ( FileNotFoundException filesNotFoundException )
{
System.err.println( "Error al crear el archivo." );
System.exit( 1 );
} // fin de catch
} // fin del método abrirArchivo
// agrega registros al archivo
public void agregarRegistros()
{
// objeto que se va a escribir en el archivo
RegistroCuenta registro = new RegistroCuenta();
Scanner entrada = new Scanner( System.in );
System.out.printf( "%s\n%s\n%s\n%s\n\n",
"Para terminar la entrada, escriba el indicador de fin de archivo ",
"cuando se le pida que escriba los datos de entrada.",
"En UNIX/Linux/Mac OS X escriba
"En Windows escriba
System.out.printf( "%s\n%s",
"Escriba el numero de cuenta (> 0), primer nombre, apellido paterno y saldo.",
"? " );
while ( entrada.hasNext() ) // itera hasta encontrar el indicador de fin de archivo
{
try // envía valores al archivo
{
// obtiene los datos que se van a enviar
registro.establecerCuenta( entrada.nextInt() ); // lee el número de cuenta
registro.establecerPrimerNombre( entrada.next() ); // lee el primer nombre
registro.establecerApellidoPaterno( entrada.next() ); // lee el apellido paterno
registro.establecerSaldo( entrada.nextDouble() ); // lee el saldo
if ( registro.obtenerCuenta() > 0 )
{
// escribe el nuevo registro
salida.format( "%d %s %s %.2f\n", registro.obtenerCuenta(),
registro.obtenerPrimerNombre(), registro.obtenerApellidoPaterno(),
registro.obtenerSaldo() );
} // fin de if
else
{
System.out.println(
"El numero de cuenta debe ser mayor que 0." );
} // fin de else
} // fin de try
catch ( FormatterClosedException formatterClosedException )
{
System.err.println( "Error al escribir en el archivo." );
return;
} // fin de catch
catch ( NoSuchElementException elementException )
{
System.err.println( "Entrada invalida. Intente de nuevo." );
entrada.nextLine(); // descarta la entrada para que el usuario intente de nuevo
} // fin de catch
System.out.printf( "%s %s\n%s", "Escriba el numero de cuenta (> 0),",
"primer nombre, apellido paterno y saldo.", "? " );
} // fin de while
} // fin del método agregarRegistros
// cierra el file
public void cerrarArchivo()
{
if ( salida != null )
salida.close();
} // fin del método cerrarArchivo
} // fin de la clase CrearArchivoTexto
CONCLUSIÓN
En este capítulo aprendimos a utilizar el procesamiento de archivos para manipular datos persistentes. Aprendimos que los datos se almacenan en las computadoras en forma de 0s y 1s, y que las combinaciones de estos valores se utilizan para formar bytes, campos, registros y en un momento dado, archivos. Comparamos los flujos basados en caracteres y los flujos basados en bytes, y presentamos varias clases para procesamiento de archivos que proporciona el paquete java.io. Utilizamos la clase file para obtener la información acerca de un archivo o directorio. Utilizamos el proceso de archivo secuencial para manipular registros que se almacenan en orden, en base al campo clave del registro. Conocimos las diferencias entre el procesamiento de archivos de texto y la serialización de objetos, y utilizamos para almacenar y obtener objetos completos.
El capítulo concluyo con una descripción general de las demás clases que proporciona el paquete java.io y un pequeño ejemplo acerca del uso de un cuadro de dialogo JFIleChooser para permitir a los usuarios al seleccionar archivos de GUI con facilidad.
Fig. 14.9: PruebaCrearArchivoTexto.java
public class PruebaCrearArchivoTexto
{
public static void main( String args[] )
{
CrearArchivoTexto aplicacion = new CrearArchivoTexto();
aplicacion.abrirArchivo();
aplicacion.agregarRegistros();
aplicacion.cerrarArchivo();
} // fin de main
} // fin de la clase PruebaCrearArchivoTexto
Fig. 14.11: LeerArchivoTexto.java
import java.io.File;
import java.io.FileNotFoundException;
import java.lang.IllegalStateException;
import java.util.NoSuchElementException;
import java.util.Scanner;
import com.deitel.jhtp7.cap14.RegistroCuenta;
public class LeerArchivoTexto
{
private Scanner entrada;
// permite al usuario abrir el archivo
public void abrirArchivo()
{
try
{
entrada = new Scanner( new File( "clientes.txt" ) );
} // fin de try
catch ( FileNotFoundException fileNotFoundException )
{
System.err.println( "Error al abrir el archivo." );
System.exit( 1 );
} // fin de catch
} // fin del método abrirArchivo
// lee registro del archivo
public void leerRegistros()
{
// objeto que se va a escribir en la pantalla
RegistroCuenta registro = new RegistroCuenta();
System.out.printf( "%-9s%-15s%-18s%10s\n", "Cuenta",
"Primer nombre", "Apellido paterno", "Saldo" );
try // lee registros del archivo, usando el objeto Scanner
{
while ( entrada.hasNext() )
{
registro.establecerCuenta( entrada.nextInt() ); // lee el número de cuenta
registro.establecerPrimerNombre( entrada.next() ); // lee el primer nombre
registro.establecerApellidoPaterno( entrada.next() ); // lee el apellido paterno
registro.establecerSaldo( entrada.nextDouble() ); // lee el saldo
// muestra el contenido del registro
System.out.printf( "%-9d%-15s%-18s%10.2f\n",
registro.obtenerCuenta(), registro.obtenerPrimerNombre(),
registro.obtenerApellidoPaterno(), registro.obtenerSaldo() );
} // fin de while
} // fin de try
catch ( NoSuchElementException elementException )
{
System.err.println( "El archivo no esta bien formado." );
entrada.close();
System.exit( 1 );
} // fin de catch
catch ( IllegalStateException stateException )
{
System.err.println( "Error al leer del archivo." );
System.exit( 1 );
} // fin de catch
} // fin del método leerRegistros
// cierra el archivo y termina la aplicación
public void cerrarArchivo()
{
if ( entrada != null )
entrada.close(); // cierra el archivo
} // fin del método cerrarArchivo
} // fin de la clase LeerArchivoTexto
Fig. 14.12: PruebaLeerArchivoTexto.java
public class PruebaLeerArchivoTexto
{
public static void main( String args[] )
{
LeerArchivoTexto aplicacion = new LeerArchivoTexto();
aplicacion.abrirArchivo();
aplicacion.leerRegistros();
aplicacion.cerrarArchivo();
} // fin de main
} // fin de la clase PruebaLeerArchivoTexto
Fig. 14.13: OpcionMenu.java
public enum OpcionMenu
{
// declara el contenido del tipo enum
SALDO_CERO( 1 ),
SALDO_CREDITO( 2 ),
SALDO_DEBITO( 3 ),
FIN( 4 );
private final int valor; // opción actual del menú
OpcionMenu( int valorOpcion )
{
valor = valorOpcion;
} // fin del constructor del tipo enum OpcionMenu
public int obtenerValor()
{
return valor;
} // fin del método obtenerValor
} // fin del tipo enum OpcionMenu
Fig. 14.14: ConsultaCredito.java
// contenido con base en el tipo de cuenta que solicita el usuario
// (saldo con crédito, saldo con débito o saldo de cero).
import java.io.File;
import java.io.FileNotFoundException;
import java.lang.IllegalStateException;
import java.util.NoSuchElementException;
import java.util.Scanner;
import com.deitel.jhtp7.cap14.RegistroCuenta;
public class ConsultaCredito
{
private OpcionMenu tipoCuenta;
private Scanner entrada;
private OpcionMenu opciones[] = { OpcionMenu.SALDO_CERO,
OpcionMenu.SALDO_CREDITO, OpcionMenu.SALDO_DEBITO,
OpcionMenu.FIN };
// lee los registros del archivo y muestra sólo los registros del tipo apropiado
private void leerRegistros()
{
// objeto que se va a escribir en el archivo
RegistroCuenta registro = new RegistroCuenta();
try // lee registros
{
// abre el archivo para leer desde el principio
entrada = new Scanner( new File( "clientes.txt" ) );
while ( entrada.hasNext() ) // recibe los valores del archivo
{
registro.establecerCuenta( entrada.nextInt() ); // lee número de cuenta
registro.establecerPrimerNombre( entrada.next() ); // lee primer nombre
registro.establecerApellidoPaterno( entrada.next() ); // lee apellido paterno
registro.establecerSaldo( entrada.nextDouble() ); // lee saldo
// si el tipo de cuenta es apropiado, muestra el registro
if ( debeMostrar( registro.obtenerSaldo() ) )
System.out.printf( "%-10d%-12s%-12s%10.2f\n",
registro.obtenerCuenta(), registro.obtenerPrimerNombre(),
registro.obtenerApellidoPaterno(), registro.obtenerSaldo() );
} // fin de while
} // fin de try
catch ( NoSuchElementException elementException )
{
System.err.println( "El archivo no esta bien formado." );
entrada.close();
System.exit( 1 );
} // fin de catch
catch ( IllegalStateException stateException )
{
System.err.println( "Error al leer del archivo." );
System.exit( 1 );
} // fin de catch
catch ( FileNotFoundException fileNotFoundException )
{
System.err.println( "No se puede encontrar el archivo." );
System.exit( 1 );
} // fin de catch
finally
{
if ( entrada != null )
entrada.close(); // cierra el objeto Scanner y el archivo
} // fin de finally
} // fin del método leerRegistros
// usa el tipo de registro para determinar si el registro debe mostrarse
private boolean debeMostrar( double saldo )
{
if ( ( tipoCuenta == OpcionMenu.SALDO_CREDITO )
&& ( saldo < 0 ) )
return true;
else if ( ( tipoCuenta == OpcionMenu.SALDO_DEBITO )
&& ( saldo > 0 ) )
return true;
else if ( ( tipoCuenta == OpcionMenu.SALDO_CERO )
&& ( saldo == 0 ) )
return true;
return false;
} // fin del método debeMostrar
// obtiene solicitud del usuario
private OpcionMenu obtenerSolicitud()
{
Scanner textoEnt = new Scanner( System.in );
int solicitud = 1;
// muestra opciones de solicitud
System.out.printf( "\n%s\n%s\n%s\n%s\n%s\n",
"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 - Finalizar ejecucion" );
try // trata de recibir la opción del menú
{
do // recibe solicitud del usuario
{
System.out.print( "\n? " );
solicitud = textoEnt.nextInt();
} while ( ( solicitud < 1 ) || ( solicitud > 4 ) );
} // fin de try
catch ( NoSuchElementException elementException )
{
System.err.println( "Entrada invalida." );
System.exit( 1 );
} // fin de catch
return opciones[ solicitud - 1 ]; // devuelve valor de enum para la opción
} // fin del método obtenerSolicitud
public void procesarSolicitudes()
{
// obtiene la solicitud del usuario (saldo de cero, con crédito o con débito)
tipoCuenta = obtenerSolicitud();
while ( tipoCuenta != OpcionMenu.FIN )
{
switch ( tipoCuenta )
{
case SALDO_CERO:
System.out.println( "\nCuentas con saldos de cero:\n" );
break;
case SALDO_CREDITO:
System.out.println( "\nCuentas con saldos con credito:\n" );
break;
case SALDO_DEBITO:
System.out.println( "\nCuentas con saldos con debito:\n" );
break;
} // fin de switch
leerRegistros();
tipoCuenta = obtenerSolicitud();
} // fin de while
} // fin del método procesarSolicitudes
} // fin de la clase ConsultaCredito
Fig. 14.15: PruebaConsultaCredito.java
public class PruebaConsultaCredito
{
public static void main( String args[] )
{
ConsultaCredito aplicacion = new ConsultaCredito();
aplicacion.procesarSolicitudes();
} // fin de main
} // fin de la clase PruebaConsultaCredito
Fig. 14.17: RegistroCuentaSerializable.java
public class RegistroCuentaSerializable implements Serializable
{
private int cuenta;
private String primerNombre;
private String apellidoPaterno;
private double saldo;
// el constructor sin argumentos llama al otro constructor con valores predeterminados
public RegistroCuentaSerializable()
{
this( 0, "", "", 0.0 );
} // fin del constructor de RegistroCuentaSerializable sin argumentos
// el constructor con cuatro argumentos inicializa un registro
public RegistroCuentaSerializable(
int cta, String nombre, String apellido, double sal )
{
establecerCuenta( cta );
establecerPrimerNombre( nombre );
establecerApellidoPaterno( apellido );
establecerSaldo( sal );
} // fin del constructor de RegistroCuentaSerializable con cuatro argumentos
// establece el número de cuenta
public void establecerCuenta( int cta )
{
cuenta = cta;
} // fin del método establecerCuenta
// obtiene el número de cuenta
public int obtenerCuenta()
{
return cuenta;
} // fin del método obtenerCuenta
// establece el primer nombre
public void establecerPrimerNombre( String nombre )
{
primerNombre = nombre;
} // fin del método establecerPrimerNombre
// obtiene el primer nombre
public String obtenerPrimerNombre()
{
return primerNombre;
} // fin del método obtenerPrimerNombre
// establece el apellido paterno
public void establecerApellidoPaterno( String apellido )
{
apellidoPaterno = apellido;
} // fin del método establecerApellidoPaterno
// obtiene el apellido paterno
public String obtenerApellidoPaterno()
{
return apellidoPaterno;
} // fin del método obtenerApellidoPaterno
// establece el saldo
public void establecerSaldo( double sal )
{
saldo = sal;
} // fin del método establecerSaldo
// obtiene el saldo
public double obtenerSaldo()
{
return saldo;
} // fin del método obtenerSaldo
} // fin de la clase RegistroCuentaSerializable
Fig. 14.18: CrearArchivoSecuencial.java
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.NoSuchElementException;
import java.util.Scanner;
import com.deitel.jhtp7.cap14.RegistroCuentaSerializable;
public class CrearArchivoSecuencial
{
private ObjectOutputStream salida; // envía los datos a un archivo
// permite al usuario especificar el nombre del archivo
public void abrirArchivo()
{
try // abre el archivo
{
salida = new ObjectOutputStream(
new FileOutputStream( "clientes.ser" ) );
} // fin de try
catch ( IOException ioException )
{
System.err.println( "Error al abrir el archivo." );
} // fin de catch
} // fin del método abrirArchivo
// agrega registros al archivo
public void agregarRegistros()
{
RegistroCuentaSerializable registro; // objeto que se va a escribir al archivo
int numeroCuenta = 0; // número de cuenta para el objeto registro
String primerNombre; // primer nombre para el objeto registro
String apellidoPaterno; // apellido paterno para el objeto registro
double saldo; // saldo para el objeto registro
Scanner entrada = new Scanner( System.in );
System.out.printf( "%s\n%s\n%s\n%s\n\n",
"Para terminar de introducir datos, escriba el indicador de fin de archivo ",
"Cuando se le pida que introduzca los datos.",
"En UNIX/Linux/Mac OS X escriba
"En Windows escriba
System.out.printf( "%s\n%s",
"Escriba el numero de cuenta (> 0), primer nombre, apellido y saldo.",
"? " );
while ( entrada.hasNext() ) // itera hasta el indicador de fin de archivo
{
try // envía los valores al archivo
{
numeroCuenta = entrada.nextInt(); // lee el número de cuenta
primerNombre = entrada.next(); // lee el primer nombre
apellidoPaterno = entrada.next(); // lee el apellido paterno
saldo = entrada.nextDouble(); // lee el saldo
if ( numeroCuenta > 0 )
{
// crea un registro nuevo
registro = new RegistroCuentaSerializable( numeroCuenta,
primerNombre, apellidoPaterno, saldo );
salida.writeObject( registro ); // envía el registro como salida
} // fin de if
else
{
System.out.println(
"El numero de cuenta debe ser mayor de 0." );
} // fin de else
} // fin de try
catch ( IOException ioException )
{
System.err.println( "Error al escribir en el archivo." );
return;
} // fin de catch
catch ( NoSuchElementException elementException )
{
System.err.println( "Entrada invalida. Intente de nuevo." );
entrada.nextLine(); // descarta la entrada para que el usuario intente de nuevo
} // fin de catch
System.out.printf( "%s %s\n%s", "Escriba el numero de cuenta (>0),",
"primer nombre, apellido y saldo.", "? " );
} // fin de while
} // fin del método agregarRegistros
// cierra el archivo y termina la aplicación
public void cerrarArchivo()
{
try // cierra el archivo
{
if ( salida != null )
salida.close();
} // fin de try
catch ( IOException ioException )
{
System.err.println( "Error al cerrar el archivo." );
System.exit( 1 );
} // fin de catch
} // fin del método cerrarArchivo
} // fin de la clase CrearArchivoSecuencial
Fig. 14.19: PruebaCrearArchivoSecuencial.java
public class PruebaCrearArchivoSecuencial
{
public static void main( String args[] )
{
CrearArchivoSecuencial aplicacion = new CrearArchivoSecuencial();
aplicacion.abrirArchivo();
aplicacion.agregarRegistros();
aplicacion.cerrarArchivo();
} // fin de main
} // fin de la clase PruebaCrearArchivoSecuencial
Fig. 14.20: LeerArchivoSecuencial.java
// y muestra cada registro.
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import com.deitel.jhtp7.cap14.RegistroCuentaSerializable;
public class LeerArchivoSecuencial
{
private ObjectInputStream entrada;
// permite al usuario seleccionar el archivo a abrir
public void abrirArchivo()
{
try // abre el archivo
{
entrada = new ObjectInputStream(
new FileInputStream( "clientes.ser" ) );
} // fin de try
catch ( IOException ioException )
{
System.err.println( "Error al abrir el archivo." );
} // fin de catch
} // fin del método abrirArchivo
// lee el registro del archivo
public void leerRegistros()
{
RegistroCuentaSerializable registro;
System.out.printf( "%-10s%-15s%-15s%10s\n", "Cuenta",
"Primer nombre", "Apellido paterno", "Saldo" );
try // recibe los valores del archivo
{
while ( true )
{
registro = ( RegistroCuentaSerializable ) entrada.readObject();
// muestra el contenido del registro
System.out.printf( "%-10d%-15s%-15s%11.2f\n",
registro.obtenerCuenta(), registro.obtenerPrimerNombre(),
registro.obtenerApellidoPaterno(), registro.obtenerSaldo() );
} // fin de while
} // fin de try
catch ( EOFException endOfFileException )
{
return; // se llegó al fin del archivo
} // fin de catch
catch ( ClassNotFoundException classNotFoundException )
{
System.err.println( "No se pudo crear el objeto." );
} // fin de catch
catch ( IOException ioException )
{
System.err.println( "Error al leer del archivo." );
} // fin de catch
} // fin del método leerRegistros
// cierra el archivo y termina la aplicación
public void cerrarArchivo()
{
try // cierra el archivo y sale
{
if ( entrada != null )
entrada.close();
System.exit( 0 );
} // fin de try
catch ( IOException ioException )
{
System.err.println( "Error al cerrar el archivo." );
System.exit( 1 );
} // fin de catch
} // fin del método cerrarArchivo
} // fin de la clase LeerArchivoSecuencial
Fig. 14.21: PruebaLeerArchivoSecuencial.java
public class PruebaLeerArchivoSecuencial
{
public static void main( String args[] )
{
LeerArchivoSecuencial aplicacion = new LeerArchivoSecuencial();
aplicacion.abrirArchivo();
aplicacion.leerRegistros();
aplicacion.cerrarArchivo();
} // fin de main
} // fin de la clase PruebaLeerArchivoSecuencial
Fig. 14.22: DemostracionFile.java
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class DemostracionFile extends JFrame
{
private JTextArea areaSalida; // se utiliza para salida
private JScrollPane panelDespl; // se utiliza para que la salida pueda desplazarse
// establece la GUI
public DemostracionFile()
{
super( "Prueba de la clase File" );
areaSalida = new JTextArea();
// agrega areaSalida a panelDespl
panelDespl = new JScrollPane( areaSalida );
add( panelDespl, BorderLayout.CENTER ); // agrega panelDespl a la GUI
setSize( 400, 400 ); // establece el tamaño de la GUI
setVisible( true ); // muestra la GUI
analizarRuta(); // crea y analiza un objeto File
} // fin del constructor de DemostracionFile
// permite al usuario especificar el nombre del archivo
private File obtenerArchivo()
{
// muestra el cuadro de diálogo de archivos, para que el usuario pueda elegir el archivo a abrir
JFileChooser selectorArchivos = new JFileChooser();
selectorArchivos.setFileSelectionMode(
JFileChooser.FILES_AND_DIRECTORIES );
int resultado = selectorArchivos.showOpenDialog( this );
// si el usuario hizo clic en el botón Cancelar en el cuadro de diálogo, regresa
if ( resultado == JFileChooser.CANCEL_OPTION )
System.exit( 1 );
File nombreArchivo = selectorArchivos.getSelectedFile(); // obtiene el archivo seleccionado
// muestra error si es inválido
if ( ( nombreArchivo == null ) || ( nombreArchivo.getName().equals( "" ) ) )
{
JOptionPane.showMessageDialog( this, "Nombre de archivo inválido",
"Nombre de archivo inválido", JOptionPane.ERROR_MESSAGE );
System.exit( 1 );
} // fin de if
return nombreArchivo;
} // fin del método obtenerArchivo
// muestra información acerca del archivo que especifica el usuario
public void analizarRuta()
{
// crea un objeto File basado en la entrada del usuario
File nombre = obtenerArchivo();
if ( nombre.exists() ) // si el nombre existe, muestra información sobre él
{
// muestra la información sobre el archivo (o directorio)
areaSalida.setText( String.format(
"%s%s\n%s\n%s\n%s\n%s%s\n%s%s\n%s%s\n%s%s\n%s%s",
nombre.getName(), " existe",
( nombre.isFile() ? "es un archivo" : "no es un archivo" ),
( nombre.isDirectory() ? "es un directorio" :
"no es un directorio" ),
( nombre.isAbsolute() ? "es una ruta absoluta" :
"no es una ruta absoluta" ), "Ultima modificacion: ",
nombre.lastModified(), "Tamanio: ", nombre.length(),
"Ruta: ", nombre.getPath(), "Ruta absoluta: ",
nombre.getAbsolutePath(), "Padre: ", nombre.getParent() ) );
if ( nombre.isDirectory() ) // imprime el listado del directorio
{
String directorio[] = nombre.list();
areaSalida.append( "\n\nContenido del directorio:\n" );
for ( String nombreDirectorio : directorio )
areaSalida.append( nombreDirectorio + "\n" );
} // fin de else
} // fin de if exterior
else // no es archivo ni directorio, imprime mensaje de error
{
JOptionPane.showMessageDialog( this, nombre +
" no existe.", "ERROR", JOptionPane.ERROR_MESSAGE );
} // fin de else
} // fin del método analizarRuta
} // fin de la clase DemostracionFile
Fig. 14.23: PruebaDemostracionFile.java
import javax.swing.JFrame;
public class PruebaDemostracionFile
{
public static void main( String args[] )
{
DemostracionFile aplicacion = new DemostracionFile();
aplicacion.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
} // fin de main
} // fin de la clase PruebaDemostracionFile