Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Los programas Java realizan las E/S a través de flujos. Un flujo es una
abstracción que consume o produce información. Todos los flujos se comportan de la
misma manera, aun cuando los dispositivos físicos reales a los que están vinculados
difieren entre si. Por lo tanto se pueden aplicar las mismas clases de E/S a cualquier tipo
de dispositivo. Java implementa flujos dentro de las jerarquías de clases que se definen
en el paquete java.io.
Java define dos tipos de flujos: de bytes y de caracteres. Los flujos de bytes
suponen un medio cómodo para gestionar la entrada y salida de bytes. Los flujos de
caracteres hacen lo propio con los caracteres y utilizan el código Unicote, y por lo tanto
se pueden internacionalizar. En algunos casos los flujos de caracteres son más eficientes
que los flujos de bytes.
En el lenguaje Java los flujos de datos se describen mediante clases que forman
jerarquías según sea el tipo de dato char Unicode de 16 bits o byte de 8 bits. A su vez,
las clases se agrupan en jerarquías según sea su función de lectura o de escritura. La
característica de internacionalización del lenguaje Java es la razón por la que existe una
jerarquía separada de clases para la lectura y escritura de caracteres. Todas estas clases
se encuentran en el paquete java.io.
Reader y Writer son las clases bases de la jerarquía para los flujos de caracteres:
Para leer o escribir datos binarios tales como imágenes o sonidos, se emplea otra
jerarquía de clases cuyas clases base son InputStream y OutputStream:
Lectura.
Las clases Reader e InputStream son similares aunque se refieren a distintos tipos de
datos, lo mismo ocurre con Writer y OutputSream. Por ejemplo, Reader proporciona
tres métodos para leer un carácter char o un array de caracteres:
int read()
int read(char buf[])
int read(char buf[], int offset, int len)
int read()
int read(byte buf[])
int read(byte buf[], int offset, int len)
La primera versión lee un byte como entero del flujo de entrada, devuelve –1 si no hay
más datos que leer. La segunda versión, lee un array de bytes devolviendo el número de
bytes leídos. La tercera versión, lee también, un array de bytes, pero nos permite
especificar, la posición de comienzo del array en la que se empiezan a guardar los bytes,
y el máximo número de bytes que se van a leer.
Escritura.
La clase Writer proporciona tres métodos para escribir un carácter char o un array de
caracteres:
int write(int c)
int write(char buf[])
int write(char buf[], int offset, int len)
int write(int c)
int write(byte buf[])
int write(byte buf[], int offset, int len)
Flujos de entrada.
Objetos FileInputStream.
Apertura de un FileInputStream.
FileInputStream miFicheroSt;
miFicheroSt = new FileInputStream( "/etc/kk" );
Lectura de un FileInputStream.
Una vez abierto el FileInputStream, se puede leer de él. El método read() tiene
muchas opciones:
Cierre de FileInputStream.
FileInputStream fis;
TextArea ta;
try {
fis = new FileInputStream( "/etc/kk" );
} catch( FileNotFoundException e ) {
/* Hacer algo */
}
try {
i = fis.read( b );
} catch( IOException e ) {
/* Hacer algo */
}
Objetos DataInputStream.
Los objetos DataInputStream se comportan como los FileInputStream. Los
flujos de datos pueden leer cualquiera de las variables de tipo nativo, como floats, ints o
chars. Generalmente se utilizan DataInputStream con ficheros binarios.
DataInputStream miDStream;
FileInputStream miFStream;
Lectura de un DataInputStream.
URL imagenSrc;
imagenSrc = new URL( "http://enterprise.com/~info" );
imagenes[0] = getImage( imagenSrc,"imagenes/pepe.gif" );
ImputStream is;
byte buffer[] = new byte[24];
is = new URL( getDocumentBase(),datos).openStream();
Ahora se puede utilizar is para leer información de la misma forma que se hace con un
objeto FileInputStream:
is.read( buffer,0,buffer.length );
Flujos de salida.
Objetos FileOutputStream.
Apertura de un FileOutputStream.
Escritura en un FileOutputStream.
Escribe un byte:
void write( int b );
Cierre de FileOutputStream.
Por ejemplo:
95-4751232,Juanito
564878,Luisa
123456,Pepe
347698,Antonio
91-3547621,Maria
class Telefonos {
static FileOutputStream fos;
public static final int longLinea = 81;
FileOutputStream miFileStream;
BufferdOutpurStream miBufferStream;
// Obtiene un controlador de fichero
miFileStream = new FileOutputStream( "/tmp/kk" );
// Encadena un stream de salida con buffer
miBufferStream = new BufferedOutputStream( miFileStream );
Streams DataOutput.
DataOutputStream miDataStream;
FileOutputStream miFileStream;
BufferedOutputStream miBufferStream;
Cada uno de los métodos write() accesibles por los FileOutputStream también lo
son a través de los DataOutputStream. También encontrará métodos complementarios a
los de DataInputStream:
Para las cadenas, se tienen dos posibilidades: bytes y caracteres. Hay que recordar que
los bytes son objetos de 8 bits y los caracteres lo son de 16 bits. Si nuestras cadenas
utilizan caracteres Unicode, debemos escribirlas con writeChars().
Contabilidad de la salida.
. . .
int numBytes = miDataStream.size() % 4;
for( int i=0; i < numBytes; i++ )
miDataStream.write( 0 );
. . .
3. Flujos de tipo objeto.
La interfaz Serializable.
import java.io.*;
public interface Serializable{
}
Para hacer una clase serializable simplemente hay que implementar la interfaz
Serializable:
Lectura/Escritura.
salida.close();
El proceso de lectura es paralelo al proceso de escritura, por lo que leer objetos del
flujo de entrada ObjectInputStream es muy simple y requiere los siguientes pasos.
3. El método readObject lee los objetos del flujo de entrada, en el mismo orden en
el que ha sido escritos. Primero un string y luego, un objeto de la clase Lista.
String str=(String)entrada.readObject();
Lista obj1=(Lista)entrada.readObject();
4. Se realizan tareas con dichos objetos, por ejemplo, desde el objeto obj1 de la
clase Lista se llama a la función miembro valorMedio, para hallar el valor medio
del array de datos, o se muestran en la pantalla:
entrada.close();
FileOutputStream("cliente.obj"));
Para reconstruir el objeto obj1 de la clase Cliente se procede del siguiente modo:
FileInputStream("cliente.obj"));
String str=(String)entrada.readObject();
Cliente obj1=(Cliente)entrada.readObject();
System.out.println("------------------------------");
System.out.println(str+obj1);
System.out.println("------------------------------");
entrada.close();
Objetos Compuestos.
FileOutputStream("figura.obj"));
System.out.println("------------------------------");
System.out.println(str+obj1);
System.out.println("------------------------------");
Entrada.close();
java.io.NotSerializableException: archivo.Punto.
La Herencia.
Se tiene una jerarquía formada por una clase base denominada Figura y dos
clases derivadas denominadas Circulo y Rectangulo. La clase base Figura implementa
la interfaz Serializable y en la clase Circulo de define una constante estática PI con una
aproximación de 4 decimales. De este modo se prueba el comportamiento de un
miembro estático en el proceso de serialización.
Para serializar objetos de una jerarquía solamente la clase base tiene que
implementar el interface Serializable:
fig1 y fig2 son dos referencias de la clase base Figura en la que se guardan objetos de
las clases derivadas Rectangulo y Circulo, respectivamente.
Para leer los datos guardados en el archivo figura.obj y reconstruir dos objetos obj1 y
obj2 de las clases Rectangulo y Circulo respectivamente, se procede de forma similar a
la estudiada en los apartados previos:
Se puede observar que obj1 y obj2 son referencias a la clase base Figura. Sin
embargo, cuando obj1 llama a la función área, devuelve (correctamente) el área del
rectángulo y cuando, obj2 llama a la función área devuelve el área del círculo. Además
aunque PI es un miembro estático de la clase Circulo, se reconstruye el objeto obj2 con
el valor del miembro estático con el que se calcula el área del círculo
Serialización Personalizada.
La función readObject lee todo lo que se ha escrito con writeObject en el mismo orden
en el que se ha escrito. Además, puede realizar otras tareas necesarias para actualizar el
estado del objeto:
packege java.io;
4. Gestión de ficheros.
Los ficheros son una fuente y destino primario de datos dentro de muchos
programas. La clase File trata directamente con ficheros y sistemas de fichero. Un
objeto file se usa para obtener o manipular la información asociada a un fichero en
disco, como los permisos, fecha, hora y directoria y para navegar por la jerarquía de
subdirectorios.
Par crear los objetos File pueden usarse los siguientes constructores:
File(String directorio)
File(String directorio, String nombreFich)
File(File dirObj, String nombreFich)
File(URI uriObj)
Ejemplo:
Una vez creado un objeto File, se puede utilizar uno de los siguientes métodos
para reunir información sobre el fichero:
Método Descripción
Nombres de fichero
String getName() Devuelve el nombre del fichero.
String getPath() Devuelve la ruta.
String getAbsolutePath() Devuelve la ruta absoluta.
String getParent() Devuelve el directorio padre.
Comprobaciones
boolean exists() Devuelve true si el fichero existe; en caso
contrario, devuelve false.
boolean canWrite() Devuelve true si se puede sobrescribir el
fichero y false en caso contrario.
boolean canRead() Devuelve true si el fichero es de lectura y
false si no lo es.
boolean isFile() Devuelve true si se le llama a través de un
fichero y false si se le llama a través de un
directorio.
boolean isDirectory() Devuelve true si el fichero es un directorio
y false si no lo es.
boolean isAbsolute() Devuelve true si el fichero tiene un
directorio absoluto si false si el directorio
es relativo.
Información general del fichero
long lastModified() Devuelve la fecha de la última
modificación del fichero.
long length() Devuelve la longitud del fichero.
Utilidades del directorio
boolean mkdir() Crea un directorio. Devuelve true si el
proceso tiene éxito y false si se produce
un fallo.
boolean mkdirs() Crea directorio y directorio padre.
String[] list() Extrae la lista de otros ficheros
Otros métodos de gran utilidad
boolean renameTo(File nuevoNombre) Renombra el fichero con el nombre
especificado en el nuevoNombre del
fichero File que realiza la llamada. Se
devolverá true en caso de que la operación
se realice con éxito y false si no se puede
cambiar el nombre del fichero.
boolean delete() Elimina el fichero de disco representado
por el objeto File que realiza la llamada.
También se puede utilizar delete() para
eliminar un directorio vacío. Devuelve
true si se consigue eliminar el fichero y
false en caso contrario.
void deleteOnExit() Elimina el fichero asociado al objeto que
llama cunado JVM termina.
boolean isHidden() Devuelve trae si el objeto que realiza la
llamada es un fichero oculto. De lo
contrario, devuelve false.
boolean setLastModified(long miliseg) Establece la hora en un fichero que realiza
la llamada que especifica miliseg, que es
el número de milisegundos desde la
medianoche del 1/1/1970 UTC.
boolean setReadOnly() Establece el fichero invocante en modo de
sólo lectura.
En el siguiente ejemplo se muestra información sobre los ficheros pasados como
argumentos en la línea de comandos:
import java.io.*;
class InfoFichero {
El método accept() devuelve true para los ficheros que especifique directorio que
deben incluirse en la lista y devuelve false para aquellos ficheros que deban exluirse.
import java.io.*;
class DirListOnly {
public static void main(String args[]) {
String dirname = “/java”;
File f1 = new File(dirname);
FilenameFilter only = new OnlyExt(“html”);
String s[] = f1.list(only);
Una variación del método list() es listFiles(), que puede resultal muy útil. Sus
formas son las siguientes:
File[] listFiles();
File[] listFiles(FilenameFilter FFObj);
File[] listFiles(FileFilter FObj);
Estos métodos devuelven la lista del fichero como una matriz de objetos File en
lugar de cómo cadenas. El primer método devuelve todos los ficheros, el segundo
devuelve sólo aquellos ficheros que satisfacen el FileName especificado. Además de
devolver una matriz de objetos File, estas dos versiones de listFiles() funcionan como
sus métodos list() equivalentes. La tercera versión de listFiles() devuelve aquellos
ficheros cuyos nombres de directorios satisfagan el filtro FileFilter especificado.
FileFilter define un solo método, accept(), al que se le llama una vez por cada fichero de
lista. Su forma general es la siguiente:
El método accept() devuelve true para los ficheros que deberían incluirse en la
lista (es decir, aquellos que coinciden con el argumento de directorioFichero), y false
para aquellos que deberían exluirse.
La versión J2SE 5 incorpora dos nuevas interfaces en java.io, Closeable y
Flushable. Estas interfaces están implementadas por algunas de las clases de E/S. Su
inclusión no aporta nuevas funciones a las clases de flujo, sino que simplemente ofrece
una manera uniforme de especificar que un flujo puede cerrarse o purgarse.
Los objetos de una clase que implemente Closeable pueden cerrarse. Esta interfaz
define el método close() :
Este método cierra el flujo que realiza la llamada, liberando cualquier recurso
que pudiera contener. Esta interfaz está implementada por todas las clases de E/S que
abren un flujo que también puede cerrarse.
Los objetos de una clase que implementa Flushable pueden ser salidas de búfer
obligadas a escribirse en el flujo al que el objeto se ha adjuntado. Esta interfaz define el
método flush():
Purgar un flujo suele hacer que la salida por búfer sea físicamente escrita en el
elemento subyacente. Esta interfaz está implementada por todas las clases de E/S que
escriben en el flujo.