lunes

INTEGRANTES

  • OFIR GIZEH VAZQUEZ PEREZ
  • PERLA GUADALUPE HERNANDEZ ARIAS
  • LAURA SANCHEZ MORALES

domingo

Introducción

El almacenamiento de datos en variables y arreglos es temporal; los datos se pierden cuando una variable local queda fuera de alcance, o cuando el programa termina. Las computadoras utilizan archivos para la retención a largo plazo de grandes cantidades de datos, incluso hasta después de que terminan los programas que crean esos datos. Usted utiliza archivos a diario, para tareas como escribir un ensayo o crear una hoja de calculo. Nos referimos a los datos que se mantienen en archivos como datos persistentes, ya que existen mas allá de la duración de la ejecución del programa. Las computadoras almacenan archivos en dispositivos de almacenamiento secundario como discos duros, discos ópticos y cintas magnéticas. En este capitulo explicaremos cómo los programas en Java crean, actualizan y procesan archivos.

Veremos la arquitectura de Java para manejar archivos mediante programación; Veremos varias clases el paquete java.io. Luego explicaremos que los datos pueden almacenarse en dos tipos distintos de archivos (de texto y binarios) y cubriremos las diferencias entre ellos.



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

// Demostración de la clase File.
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

// Prueba de la clase DemostracionFile.
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

Escriba aqui el nombre del archivo o directorio: C:\Archivos de programa\Java\jdk1.6.0_07\demo\jfc
jfc existe
no es un archivo
es un directorio
es ruta absoluta
Ultima modificacion: 1237826446234
Tamanio: 0
Ruta: C:\Archivos de programa\Java\jdk1.6.0_07\demo\jfc
Ruta absoluta: C:\Archivos de programa\Java\jdk1.6.0_07\demo\jfc
Padre: C:\Archivos de programa\Java\jdk1.6.0_07\demo

Contenido del directorio:

CodePointIM
FileChooserDemo
Font2DTest
Java2D
Metalworks
Notepad
SampleTree
Stylepad
SwingApplet
SwingSet2
TableExample

Fig. 14.5: PruebaDemostracionFile.java

// Prueba de la clase DemostracionFile.
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

Escriba aqui el nombre del archivo o directorio: C:\Archivos de programa\Java\jdk1.6.0_07\demo\jfc\Java2D\readme.txt
readme.txt existe
es un archivo
no es un directorio
es ruta absoluta
Ultima modificacion: 1237826432546
Tamanio: 7518
Ruta: C:\Archivos de programa\Java\jdk1.6.0_07\demo\jfc\Java2D\readme.txt
Ruta absoluta: C:\Archivos de programa\Java\jdk1.6.0_07\demo\jfc\Java2D\readme.txt
Padre: C:\Archivos de programa\Java\jdk1.6.0_07\demo\jfc\Java2D

Fig. 14.5: RegistroCuenta.java

// Fig. 14.5: RegistroCuenta.java
// Una clase que representa un registro de información
package com.deitel.jhtp7.cap14; // se empaqueta para reutilizarla

public class RegistroCuenta
{
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

// Uso de la clase Formatter para escribir datos en un archivo de texto.
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 d y oprima Intro",
"En Windows escriba z y oprima Intro" );

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.