sábado, 29 de junio de 2013

Flujos ObjectInputStream Java

Los objetos guardados en archivos con flujos de la clase ObjectOutputStream se recuperan, se
leen, con flujos de entrada del tipo ObjectInputStream. Esta clase es una extensión de InputStream,
además implementa la interfaz DataInput; por ello dispone de los diversos métodos de entrada
(read) para cada uno de los tipos de datos, readInt( )… El método más interesante definido
por la clase ObjectInputStream es readObject( ); lee un objeto del flujo de entrada (del archivo
asociado al flujo de bajo nivel). Este objeto se escribió en su momento con el método writeObject(
).
public Object readObject( ) throws IOException;
El constructor de flujos ObjectInputStream tiene como entrada otro flujo, de bajo nivel, de
cualquier tipo derivado de InputStream, por ejemplo FileInputStream, asociado con el archivo
de objetos. A continuación se crea un flujo de entrada para leer los objetos del archivo "archivoObjets.
dat":
ObjectInputStream obje = new ObjectInputStream(
new FileInputStream("archivoObjets.dat "));
El constructor levanta una excepción si, por ejemplo, el archivo no existe,..., del tipo ClassNotFoundException,
o bien IOException; es necesario poder capturar estas excepciones.




EJEMPLO PRACTICO:


Se desea guardar en un archivo los libros y discos de que disponemos. Los datos de interés para un
libro son: título, autor, editorial, número de páginas; para un disco: cantante, título, duración en minutos,
número de canciones y precio.
Se podría diseñar una jerarquía de clases que modelase los objetos libro, disco,… Sin embargo, el
ejercicio sólo pretende mostrar cómo crear objetos persistentes; declara directamente la clase Libro
y Disco con la propiedad de ser “serializables” (implementan la interfaz java.io.Serializable).
La clase principal crea un flujo de salida para objetos; según los datos que introduce el usuario se instancia
un tipo de objeto Disco o Libro y con el método writeObject( ) se escribe en el flujo.


import java.io.*;
class Libro implements Serializable
{
private String titulo;
private String autor;
private String editorial;
private int pagina;
public Libro( )
{
titulo = autor = editorial = null;
}
public Libro(String t, String a, String e, int pg)
{
titulo = t;
autor = a;
editorial = e;
pagina = pg;
}
public void entrada(BufferedReader ent) throws IOException
{
System.out.print("Titulo: "); titulo = ent.readLine( );
System.out.print("Autor: "); autor = ent.readLine( );
System.out.print("Editorial: "); editorial = ent.readLine( );
System.out.print("Páginas: ");
pagina = Integer.parseInt(ent.readLine( ));
}
}


class Disco implements Serializable
{
private String artista;
private String titulo;
private int numCancion, duracion;
private transient double precio;
public Disco( )
{
artista = titulo = null;
}
public Disco(String a, String t, int n, int d, double p)
{
titulo = t;
artista = a;
numCancion = n;
duracion = d;
precio = p;
}
public void entrada(BufferedReader ent) throws IOException
{
System.out.print("Cantante: "); artista = ent.readLine( );
System.out.print("Titulo: "); titulo = ent.readLine( );


System.out.print("Canciones: ");
numCancion = Integer.parseInt(ent.readLine( ));
System.out.print("Duración(minutos): ");
duracion = Integer.parseInt(ent.readLine( ));
System.out.print("Precio: ");
precio = Double.valueOf(ent.readLine( )).doubleValue( );
}
}
public class Libreria
{
public static void main (String [ ] a)
{
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in));
File mf = new File("libreria.dat");
ObjectOutputStream fobj = null;
Libro libro = new Libro( );
Disco disco = new Disco( );
int tipo;
boolean mas = true;
try {
fobj = new ObjectOutputStream(new FileOutputStream(mf));
do {
System.out.println
("Pulsa L(libro), D(disco), F(finalizar)");
tipo = System.in.read( );
System.in.skip(2); // salta caracteres fin de línea
switch (tipo) {
case 'L':

case 'l': libro = new Libro( );
libro.entrada(br);
fobj.writeObject(libro);
break;
case 'D':
case 'd': disco = new Disco( );
disco.entrada(br);
fobj.writeObject(disco);
break;
case 'F':
case 'f': fobj.close( );
mas = false;
}
} while (mas);
}
catch (IOException e)
{
e.printStackTrace( );
}
}
}




BufferedReader Java

La lectura de archivos de texto se realiza con un flujo que almacena los caracteres en un búfer intermedio.
Los caracteres no se leen directamente del archivo sino del búfer; con esto se consigue más
eficiencia en las operaciones de entrada. La clase BufferReader permite crear flujos de caracteres
con búfer, es una forma de organizar el flujo básico de caracteres del que procede el texto; esto se
manifiesta
en que al crear el flujo BufferReader se inicializa con un flujo de caracteres de tipo
InputStreamReader.


El constructor de la clase tiene un argumento de tipo Reader, un FileReader o un InputStreamReader.
El flujo creado dispone de un búfer de un tamaño, normalmente suficiente; el tamaño
del búfer se puede especificar en el constructor con un segundo argumento aunque no resulta
necesario. Ejemplos de flujos con búfer:
File mf = new File("C:\listados.txt");
FileReader fr = new FileReader(mf);
BufferedReader bra = new BufferedReader(fr);
File mfz = new File("Complejo.dat");
BufferedReader brz = new BufferedReader(
new InputStreamReader(
new FileInputStream(mfz)));

La clase BufferedReader deriva directamente de la clase Reader. Entonces, dispone de los
métodos read( ) para leer un carácter, o bien un arreglo de caracteres. El método más importante es
readLine( ):
public String readLine( ) throws IOException;
El método lee una línea de caracteres, termina con el carácter de fin de línea, y devuelve una cadena
con la línea leída (no incluye el carácter fin de línea). Puede devolver null si lee la marca de fin
de archivo.


Otro método interesante es close( ), cierra el flujo y libera los recursos asignados. El fin de la
aplicación Java también cierra los flujos abiertos, aunque es recomendable cerrar un flujo que no se
va a utilizar.
public void close( ) throws IOException




Flujos PrintStream Java

La clase PrintStream deriva directamente de FilterOutputStream. La característica más importante
es que dispone de métodos que añaden la marca de fin de línea. Los flujos de tipo PrintStream
son de salida, se asocian con otro flujo de bajo nivel, de bytes, que a su vez se crea asociado a un archivo
externo. Por ejemplo, mediante el flujo fjp se puede escribir cualquier tipo de dato; los bytes
que ocupa cada dato se vuelcan secuencialmente en Complex.dat
fjp = new PrintStream(new FileOutputStream("Complex.dat"));
Los métodos de esta clase, print( ) y println( ) están sobrecargados para poder escribir
desde cadenas hasta cualquiera de los datos primitivos; println( ) escribe un dato y a continuación
añade la marca de fin de línea.
A continuación están los métodos más importantes:
public PrintStream(OutputStream destino)
Crea un objeto asociado con cualquier objeto de salida pasado como argumento.
public PrintStream(OutputStream destino, boolean flag)
Crea un objeto asociado con objeto de salida pasado como argumento y si el segundo argumento
es true se produce un automático volcado al escribir el fin de línea.
public void flush( )
Vuelca el flujo actual.


public void print(Object obj)
Escribe la representación del objeto obj en el flujo.
public void print(String cad)
Escribe la cadena en el flujo.
public void print(char c)
Escribe el carácter c en el flujo.
método print( ) para cada tipo de dato primitivo.
public void println(Object obj)
Escribe la representación del objeto obj en el flujo y el fin de línea.
public void println(String cad)
Escribe la cadena en el flujo y el fin de línea.
catch (IOException io)
{
System.out.println("Anomalía al leer flujo de entrada, "
+ io.getMessage( ));
return; // termina la ejecución
}
finally {
try
{
obfl.close( );
}
catch (IOException er)
{
er.printStackTrace( );
}
}
// termina el proceso, escribe la temperatura máxima
System.out.println("\n La temperatura máxima: " + (float)mxt);
}
}


public void println(char c)
Escribe el carácter c en el flujo y el fin de línea.
método println( ) para cada tipo de dato primitivo


Nota de programación
El objeto definido en la clase System: System.out es de tipo PrintStream, asociado,
normalmente, con la pantalla. Por ello se han utilizado los métodos:
System.out.print( );
System.out.println( );

Archivos y flujos en Java

Los archivos tienen como finalidad guardar datos de forma permanente; una vez que acaba la aplicación,
los datos siguen disponibles para que otra aplicación pueda recuperarlos, para su consulta o modificación.
El proceso de archivos en Java se hace mediante el concepto de flujo (stream) o canal, o también
denominado secuencia. Los flujos pueden estar abiertos o cerrados, conducen los datos entre el programa
y los dispositivos externos. Con las clases y sus métodos proporcionados por el paquete java.io
se pueden tratar archivos secuenciales, de acceso directo, archivos indexados, etcétera.


Flujos y archivos

Un fichero (archivo) de datos, o simplemente un archivo, es una colección de registros relacionados
entre sí con aspectos en común y organizados para un propósito específico. Por ejemplo, un fichero
de una clase escolar contiene un conjunto de registros de los estudiantes de esa clase.
Un archivo en una computadora es una estructura diseñada para contener datos, los cuales están
organizados de tal modo que puedan ser recuperados fácilmente, actualizados o borrados y almacenados
de nuevo en el archivo con todos los cambios realizados.
Según las características del soporte empleado y el modo en que se han organizado los registros,
se consideran dos tipos de acceso a los registros de un archivo:
• acceso secuencial,
• acceso directo.

El acceso secuencial implica el acceso a un archivo según el orden de almacenamiento de sus registros,
uno tras otro.
El acceso directo implica el acceso a un registro determinado, sin que ello implique la consulta de
los registros precedentes. Este tipo de acceso sólo es posible con soportes direccionales.
En Java un archivo es, sencillamente, una secuencia de bytes, que son la representación de los datos
almacenados. Java dispone de clases para trabajar las secuencias de bytes como datos de tipos básicos
(int, double, String ...); incluso, para escribir o leer del archivo objetos. El diseño del archivo es el
que establece la forma de manejar las secuencias de bytes, con una organización secuencial, o bien de
acceso directo.
Un flujo (stream) es una abstracción que se refiere a una corriente de datos que fluyen entre un
origen o fuente (productor) y un destino o sumidero (consumidor). Entre el origen y el destino debe
existir una conexión o canal ( pipe) por la que circulen los datos. La apertura de un archivo supone establecer
la conexión del programa con el dispositivo que contiene el archivo; por el canal que comunica
el archivo con el programa van a fluir las secuencias de datos.
Abrir un archivo supone crear un objeto que queda asociado con un flujo. Al comenzar la ejecución
de un programa Java se crean automáticamente tres objetos de flujo, son tres canales por los que
pueden fluir datos, de entrada o de salida. Éstos son objetos definidos en la clase System:



• System.in; entrada estándar; permite la entrada al programa de flujos de bytes desde el teclado.
• System.out; salida estándar; permite al programa la salida de datos por pantalla.
• System.err; salida estándar de errores; permite al programa salida de errores por pantalla.
En Java, un archivo es simplemente un flujo externo, una secuencia de bytes almacenados en un
dispositivo externo (normalmente en disco). Si el archivo se abre para salida, es un flujo de archivo de
salida. Si el archivo se abre para entrada, es un flujo de archivo de entrada. Los programas leen o
escriben
en el flujo, que puede estar conectado a un dispositivo o a otro. El flujo es por tanto una abstracción
de tal forma que las operaciones que realizan los programas son sobre el flujo independientemente
del dispositivo al que esté asociado.


A tener en cuenta
El paquete java.io agrupa al conjunto de clases e interfaces necesarios para procesar archivos.
Es necesario utilizar clases de este paquete; por consiguiente, se debe incorporar al programa
con la sentencia import java.io.*.

Información de un archivo
Con los métodos de la clase File se obtiene información relativa al archivo o ruta con que se ha inicializado
el objeto. Así, antes de crear un flujo para leer de un archivo es conveniente determinar si el
archivo existe; en caso contrario no se puede crear el flujo. A continuación se exponen los métodos
más útiles para conocer los atributos de un archivo o un directorio.
public boolean exists( )
Devuelve true si existe el archivo (o el directorio).
public boolean canWrite( )
Devuelve true si se puede escribir en el archivo, si no es de sólo lectura.
public boolean canRead( )
Devuelve true si es de sólo lectura.
public boolean isFile( )
Devuelve true si es un archivo.
public boolean isDirectory( )
Devuelve true si el objeto representa a un directorio.
public boolean isAbsolute( )
Devuelve true si el directorio es la ruta completa.
public long length( )
Devuelve el número de bytes que ocupa el archivo. Si el objeto es un directorio devuelve cero.


public long lastModified( )
Devuelve la hora de la última modificación. El número devuelto es una representación interna
de la hora, minutos y segundos de la última modificación, sólo es útil para establecer
comparaciones con otros valores devueltos por el mismo método.
También dispone de métodos que modifican el archivo: cambiar de nombre, marcar de sólo lectura.
Para los directorios, tiene métodos para crear uno nuevo, obtener una lista de todos los elementos
(archivos o subdirectorios) del directorio. Algunos de estos métodos se escriben a continuación.
public String getName( )
Devuelve una cadena con el nombre del archivo o del directorio con que se ha inicializado
el objeto.
public String getPath( )
Devuelve una cadena con la ruta relativa al directorio actual.
public String getAbsolutePath( )
Devuelve una cadena con la ruta completa del archivo o directorio.
public boolean setReadOnly( )
Marca al archivo para que no se pueda escribir, de sólo lectura.
public boolean delete( )
Elimina el archivo o directorio (debe estar vacío).
public boolean renameTo(File nuevo)
Cambia el nombre del archivo con que ha sido inicializado el objeto por el nombre que contiene
el objeto pasado como argumento.
public boolean mkdir( )

Crea el directorio con el que se ha creado el objeto.
public String[ ] list( )
Devuelve un array de cadenas, cada una contiene un elemento (archivo o directorio) del directorio
con el que se ha inicializado el objeto.