UNIVERSIDAD
CATOLICA DE COLOMBIA
FACULTAD
DE INGENIERIA DE SISTEMAS
CURSO: JAVA BASICO
PROFESOR: EMERSON
CASTAÑEDA SANABRIA
TEMA: Entrada y Salida
OBJETIVOS:
CONTENIDO:
DESARROLLO:
1.
Flujos
La
entrada y salida en java se basa en el uso de flujos. Los flujos son secuencias
de bytes que viajan desde un origen a un destino a
través de una vía de comunicación. Cuando un programa escribe en un flujo es el
origen de este. Cuando lee desde un flujo, es el destino de éste. La vía de comunicación depende del tipo de E/S
que se realice y puede consistir en trasferencias de memoria a memoria,
sistemas de archivos, redes y otras formas de E/S.
Los
flujos no representan una cuestión compleja. Su potencia reside en la capacidad
de abstraer los detalles de la vía de comunicación desde las operaciones de
entrada y salida. Esto permite llevar a cabo procesos de entrada y salida
mediante un conjunto habitual de métodos. Estos métodos pueden modificarse y
ampliarse para que proporcionen una mayor capacidad de E/S.
2.
Clases de java para Entrada y Salida
Java
define dos clases principales de flujos: InputStream y OutputStream. A partir
de estos flujos pueden establecerse subclases a fin de que proporcionen
diversas funciones de E/S.
A
continuación se muestra la distribución de parte de la jerarquía de clases del paquete java.io:
class java.io.InputStream
class java.io.ByteArrayInputStream
class java.io.FileInputStream
class java.io.FilterInputStream
class java.io.BufferedInputStream
class java.io.DataInputStream
(implements java.io.DataInput)
class java.io.LineNumberInputStream
class java.io.PushbackInputStream
class java.io.ObjectInputStream
(implements java.io.ObjectInput,
java.io.ObjectStreamConstants)
class java.io.PipedInputStream
class java.io.SequenceInputStream
class java.io.StringBufferInputStream
class java.io.OutputStream
class java.io.ByteArrayOutputStream
class java.io.FileOutputStream
class java.io.FilterOutputStream
class java.io.BufferedOutputStream
class java.io.DataOutputStream
(implements java.io.DataOutput)
class java.io.PrintStream
class java.io.ObjectOutputStream
(implements java.io.ObjectOutput,
java.io.ObjectStreamConstants)
class java.io.PipedOutputStream
Las clases
InputStream y OutputStream poseen subclases complementarias. Por ejemplo ambas
tienen subclases para realizar procesos de entrada y salida por medio de Buffers de memoria, archivos y canales. Las subclases de
InputStream se encargan de la entrada y las subclases de OutputStream de la
salida.
La clase
InputStream
La clase
InputStream es una clase abstracta que constituye los cimientos da la jerarquía
de la clase Input de java. Como tal, proporciona
métodos que son heredados pos todas las clases InputStream.
·
El metodo
read()
El metodo read() es el mas importante de la jerarquía de clases
InputStream. Lee un byte de datos desde un flujo de
entrada y se bloquea si no hay datos disponibles. Cuando se bloquea un método,
hace que el hilo en el que se esta ejecutando espere hasta que estén disponibles los datos. Esto no se supone un
problema en programas divididos en múltiples hilos. El método read()
adopta diversas formas sobrecargadas. Pueden leer un único byte
o un arreglo de bytes en función de la forma que haya
adoptado. Devuelve el número de bytes leídos o -1 si
se encuentra un final de archivo sin haber leído ningún dato de éste.
·
El método available()
El método available()
devuelve el numero de bytes que pueden leerse sin
ocasionar un bloqueo. Se utiliza para examinar el flujo de entrada y averigua
la cantidad de datos disponibles. Sin embargo, en función del tipo de flujo de
entrada quizás no de el resultado esperado o no sea util,
razon por la cual no es buena idea fiarse ciegamente
de este método para realizar procesos de entrada.
·
El método close()
El método close()
cierra un flujo de entrada y libera los recursos asociados a éste. En todos los
casos es buena costumbre el cerrar un flujo para garantizar la finalización
correcta de los procesos.
·
El método skip()
El método skip()
omite un numero especifico de bytes de entrada. Como
parámetro utiliza un valor long.
La clase OutputStream
La clase
OutputStream es una clase abstracta que constituye la base de la jerarquía de
flujo de salida. Proporciona un conjunto de métodos que son análogos a los
métodos de InputStream.
·
El método write()
El método write()
permite escribir bytes en el flujo de salida.
Proporciona tres formas sobrecargadas para escribir un único byte, un arreglo de bytes o un
fragmento de u arreglo. El método write(), al igual que el método read(),
puede bloquearse en el momento en que intenta escribir en un flujo. El bloqueo
pone en modo de espera al hilo que esta ejecutando el método write()
hasta que no termina la operación de grabación.
El método flush()
El método flush()
hace que todo dato almacenado en buffer se escriba inmediatamente en el flujo
de salida. Algunas clases de OutputStream soportan la función de almacenamiento
provisional y anulan este método a fin de vaciar sus buffers
y escribir todos los datos almacenados provisionalmente en el flujo de salida.
El medodo close()
Por lo
general es mas importante cerrar los flujos de entrada que los de salida, de
modo que cualquier dato que se escribe en el flujo se almacena antes de
designarlo y perderlo. El método close() de OutputStream se utiliza del mismo modo que
InputStream.
3.
Lectura y Escritura de Archivos
Java
permite la escritura y lectura de archivos mediante flujos con las clases File,
FileDescriptor, FileInputStream y FileOutputStream. Además, soporta la E/S de
acceso aleatorio o directo mediante las clases File, FileDescriptor y RandomAccessFile.
La clase File
La
clase fie se utiliza para acceder a objetos de
archivo y de directorio. Emplea los convenios de nomenclatura del sistema
operativo local. La clase File agrupa estas convenciones mediante constantes de
clase.
File
incorpora constructores para crear archivos o directorios, estos constructores
admiten rutas de acceso y nombre de archivo y directorio tanto absolutos como
relativos.
La
clase file proporciona un gran numero de métodos de acceso que pueden utilizarse
para crear, borra y renombrar archivos, además de proporcionar acceso a la ruta
y el nombre del archivo y determinar si un objeto File es un archivo o un
directorio. Asimismo estos métodos compruebas los permisos de acceso para
lectura y escritura.
La clase FileDescriptor
La
clase FileDescriptor permite acceder a los descriptores de un archivo
mantenidos por los sistemas operativos para acceder a archivos o directorios.
Esta clase no permite conocer la información específica que mantiene el sistema
operativo. Proporciona un único método, valid(), que se emplea para determinar si un objeto de descriptor
de archivo es valido en su momento.
La clase FileInputStream
La
clase FileInputStream permite leer los datos de un archivo en forma de flujo.
Los objetos de la clase FileInputStream se crean utilizando como argumento una
cadena de nombre de archivo o un objeto File o FileDescriptor. FileInputStream
anula los métodos de la clase InputStream y proporciona dos métodos nuevos, finalize()
y getFD(). El método finalize() se emplea para
cerrar un flujo cuando es procesado de retorno de recursos de java. El método getFD()
se utiliza para obtener acceso al FileDescriptor que esta asociado a un flujo
de entrada.
La clase FileOutputStream
La
clase FileOutputStream permite escribir una salida en un flujo de archivo. Los
objetos de la clase FileOutputStream se crean del mismo modo que los de la
clase FileInputStream. Anula los métodos de la clase OutputStream y soporta los
métodos finalize() y getFD() al igual que FileInputStream.
La clase RandomAccessFile
La
clase RandomAccessFile ofrese la posibilidad de
realizar operaciones de E/S directamente en posiciones especificas de un
Archivo. El nombre “random access”
se basa en el hecho de que es posible leer y escribir datos en ubicaciones
aleatorias de un archivo en lugar de un flujo continuo de información. El
método de acceso aleatorio lo soporte el método seek(), que permite asignar
una ubicación arbitraria al puntero correspondiente a la posición actual del archivo. RandomAccessFile
implementa las interfaces DataInput y DataOutput. Esto ofrece la posibilidad de realizar
operaciones de entrada y salida utilizando todo los objetos y tipo des datos
primitivos.
La
clase RandomAccessFile también soporta la posibilidad de establecer permisos de
básicos de lectura y escritura de archivos, mediante los cuales autoriza acceso
de solo lectura o solo escritura. Para ellos se transfiere un argumento r o rw de modo al constructor de RandomAccessFile, con el que
se indica el tipo de acceso al archivo.
RandomAccessFile
introduce varios métodos nuevos, además de los que hereda de Object e implementa de DataInput
y DataOutput. Estos métodos incluyen seek(), getFielPointer() y length(). Los
anteriores métodos asignan al puntero al archivo una ubicación específica,
devuelven la posición actual del puntero y la longitud del archivo en bytes respectivamente.
4.
Lectura y Escritura de Objetos en archivos
Con
el fin de aprovechar las características de un lenguaje orientado a objetos, en
todo su esplendor, evitando así hacer híbridos en el almacenamiento de los
objetos persistentes (combinar objetos con relacional), es decir, en lugar de
almacenar registros equivalentes a los datos encapsulados en un objeto y luego
recuperarlos para crear una instancia del mismo. Existe la posibilidad de
almacenar los objetos tal cual como se encuentren en determinado momento y
posteriormente hacer la recuperación de los mismos sin hacer esfuerzos
adicionales en conversiones intermedias para llevarlos a una representación
relacional, es de esta manera como: guardamos objetos y recuperamos objetos.
Las
clases que intervienen para conseguir este objetivo, son las siguientes: FileOutputStream, ObjectOutputStream
para la escritura de objetos y FileInputStream, ObjectInputStream para la recuperacion
de objetos previamente almacenados en un archivo. Otro elemento que hace parte
del procedimiento es la Interface Serializable
del paquete java.io. esta
posibilita a las clases que la implementan, su representación como cadenas de bytes para asi ser almacenados y
recuperados como información binaria.
A
continuación se presenta un ejemplo sencillo de cómo es posible llevar a cabo
estas operaciones:
Como
primera medida es necesario que las clases de los objetos a almacenar
implementen la interface Serializable,
a continuación un ejemplo con una clase llamada ObjGuardable.
class ObjGuardable implements Serializable{
private int i;
private float f;
private boolean b;
private String str1;
public static String str2;
ObjGuardable(){
i=10;f=5.5f;b=true;str1="abc";
str1=str2;
}
ObjGuardable(int p1,float
p2,boolean p3, String p4){
i=p1;f=p2;b=p3;str1=p4;
str2=str1;
}
public String toString(){
String
aux= "i="+i+"
f=" +f+" b="+b+" str1="+str1+" str2="+str2;
return aux;
}
}
Como
se puede apreciar la clase ObjGuardable implementa la interface
Serializable , lo que permite que sus instancias se puedan representar
como cadena de bytes. De tal manera ya se cuenta con
objetos con capacidades para ser representados como una cadenas de bytes y así posteriormente ser almacenados y recuperados en
un archivo de datos.
A
continuación la clase LeeEscObjetos, una clase que utiliza intancias
de la clase ObjGuardable junto con las clases mencionadas, para llevar a cabo el
almacenamiento y la recuperación de objetos en un archivo.
import java.io.*;
public class LeeEscObjetos
{
public static void main(String arg[]){
ObjGuardable
og1= new ObjGuardable();
ObjGuardable
og2= new ObjGuardable(21,23.3f,true,"cadena");
try{
FileOutputStream ostream = new FileOutputStream("t.tmp");
ObjectOutputStream oos = new ObjectOutputStream(ostream);
oos.writeObject(og1);
oos.writeObject(og2);
oos.flush();
ostream.close();
FileInputStream istream = new FileInputStream("t.tmp");
ObjectInputStream ois = new ObjectInputStream(istream);
ObjGuardable
ogr1 = (ObjGuardable)ois.readObject();
ObjGuardable
ogr2 = (ObjGuardable)ois.readObject();
istream.close();
System.out.println("1er
objeto almacenado: "+og1);
System.out.println("2do objeto almacenado: "+og2);
System.out.println("1er objeto recuperado: "+ogr1);
System.out.println("2do objeto recuperado: "+ogr2);
}
catch(Exception e){
e.printStackTrace();
}
}
}
Básicamente
la clase LeeEscObjetos crea dos instancias de la clase ObjGuardable, los
objetos og1 y og2. Luego procede a la creación de un flujo de salida al archivo
t.tmp que se le asocia a un objeto de la clase ObjecOutputStream, objeto mediante el cual se realiza la
escritura de las instancias de la clase ObjGuardable en el archivo.
El
segundo paso consiste el la creación de un flujo de entrada desde el archivo t.tmp, asociado a una instancias de la clase ObjectInputStream, a través de la cual se recuperan
instancias de la clase ObjGuardable previamente almacenadas en dos nuevas
instancias de la misma clase, llamadas ogr1 y ogr2. Para terminar se comprueba
la información encapsulada en cada uno de los objetos, imprimiendo la
información en la consola.