Vous êtes sur la page 1sur 19

FLUJO DE BITES Y CADENAS

Stream
Cualquier programa realizado en Java que necesite llevar a
cabo una operacin de I/O lo har a travs de un stream. Un
stream, cuya traduccin literal es "flujo", es una abstraccin
de todo aquello que produzca o consuma informacin.
Podemos ver a este stream como una entidad lgica. La
vinculacin de este stream al dispositivo fsico la hace el
sistema de entrada y salida de Java. Se ve pues la eficacia de
esta implementacin pues las clases y mtodos de I/O que
necesitamos emplear son las mismas independientemente del
dispositivo con el que estemos actuando, luego, el ncleo de
Java, sabr si tiene que tratar con el teclado, el monitor, un
sistema de ficheros o un socket de red liberando a nuestro
cdigo de tener que saber con quin est interactuando.

Java define dos tipos de streams:

Byte streams : Nos proporciona un medio adecuado


para el manejo de entradas y salidas de bytes y su uso
lgicamente est orientado a la lectura y escritura de
datos binarios. El tratamiento del flujo de bytes viene
gobernado por dos clases abstractas que son
InputStream y OutputStream. Cada una de estas
clases abstractas tienen varias subclases concretas que
controlan las diferencias entre los distintos dispositivos
de I/O que se pueden utilizar. As mismo, estas dos clases
son las que definen los mtodos que sus subclases
tendrn implementados y, de entre todas, destacan las
clases read() y write() que leen y escriben bytes de datos
respectivamente.
Character streams : Proporciona un medio conveniente
para el manejo de entradas y salidas de caracteres.
Dichos flujos usan codificacin Unicode y, por tanto, se
pueden internacionalizar. Una observacin: Este es un

modo que Java nos proporciona para manejar caracteres


pero al nivel ms bajo todas las operaciones de I/O son
orientadas a byte. Al igual que la anterior el flujo de
caracteres tambin viene gobernado por dos clases
abstractas: Reader y Writer. Dichas clases manejan
flujos de caracteres Unicode. Y tambin de ellas derivan
subclases concretas que implementan los mtodos
definidos en ellas siendo los ms destacados los mtodos
read() y write() que, en este caso, leen y escriben
caracteres de datos respectivamente.

Los streams predefinidos.

Para comprender un poco mejor cmo funciona el paquete de


I/O, veamos cmo trabaja realmente la clase System.
System define tres campos que son in, out y err que
corresponden a la entrada estndar, la salida estndar y la
salida estndar de errores. System.in es un objeto de tipo
InputStream mientras que los otros dos son de tipo
PrintStream. La pregunta que ahora te hars es cmo es
posible que si yo uso la clase Sytem para mandar texto , por
ejemplo a la salida, sea de tipo
Byte? Pues bien, esto se soluciona haciendo un wrapping
(envoltorio) de la clase para convertirla a un flujo de
caracteres.

Lectura de consola.
La entrada de consola, como sabemos, la obtenemos leyendo
de System.in. Para conseguir un flujo de caracteres
envolvemos
dicha
clase
en
un
objeto
del
tipo
BufferedReader, el cual soporta un flujo de entrada
buferizado.
Atendiendo a las especificaciones de esta clase, el parmetro
que se le pasa es el stream de entrada que es de tipo
Reader, el cual, como sabemos es abastracto por lo que
recurriremos a una de sus subclases, en nuestro caso ser
InputStreamReader que convierte bytes a caracteres. Otra
vez ms, atendiendo a la especificacin de esta ltima clase

vemos que el parmetro que se le pasa es de tipo


InputStream, o sea, la entrada orientada a byte que en
nuestro caso es System.in. Ya est, ya hemos asociado un
dispositivo fsico (el teclado) a un stream orientado a
caracteres mediante el wrapping de la clase System con la
clase BufferedReader. Resumamos los pasos:
1. BufferedReader (Reader input); clase que recibe un flujo de
caracteres de entrada.
2. InputStreamReader ( InputStream input2) ; clase que
convierte de byte a carcter.
3. BufferedReader br = new BufferedReader(new
InputStreamReader(System.in); br es un
Character Stream que se linka a la consola a traves de la clase
System.in la cual hemos tenido
que wrappear para convertir de byte a char.
Ejemplo 1. Lectura de consola.
//En este ejemplo leemos de consola cadenas de caracteres.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class LecturaStringConsola {
Public static void main (String args []) throws IOException {
String cadena;
BufferedReader br;
//Creamos un BufferedReader a travs de System.in
br = new BufferedReader (new InputStreamReader
(System.in));
System.out.println("Empieza a escribir, 'stop' para salir");
//leemos cadena de caracteres mediante readLine ().
do {
cadena = br.readLine ();
System.out.println (cadena);
} while (!cadena.equals("stop"));
}
}//Fin LecturaStringConsola

Imprimir a consola.

Lo que siempre hacemos es imprimir mediante System.out


pero en una aplicacin ms formal haremos uso de la clase
PrintWriter que soporta flujos de caracteres. Esta clase
contiene los mtodos print() y println() para todos los tipos
por lo que se podrn usar igual que lo hacamos con
System.out. Si un argumento no es de un tipo simple,
entonces, los mtodos de
PrintWriter llaman al mtodo toString() y luego imprimen el
resultado.
Ejemplo 2. Imprimir a pantalla.
//En el siguiente ejemplo bsico imprimimos a consola
diferentes tipos de datos primitivos.
import java.io.PrintWriter;
public class Imprimir {
public static void main(String args[]) {
/*
El constructor toma como parmetros un objeto de tipo
OutputStream del cual deriva PrintStream, por tanto, ya
tenemos linkada la clase con el dispositivo de salida (la
consola).
*/
PrintWriter pw = new PrintWriter(System.out, true);
pw.println("Imprime una cadena de texto");
int i = 15;
pw.println("Imprime un entero " + i);
double d = 6.8e-9;
pw.println("Imprime un double " + d);
}
}

Lectura y escritura de ficheros.


En Java, todos los ficheros son orientados a byte por lo que
nos proporciona mtodos para leer y escribir desde/a un
fichero. No obstante, tambin nos permite hacer wrapping
de dicho flujo orientado a byte para convertirlo a un objeto
basado en caracteres.
Las dos principales clases que nos posibilitan trabajar con los
ficheros son FileInputStream y FileOutputStream las

cuales crean un enlace entre el flujo de bytes y el fichero. Para


abrir un fichero simplemente le pasamos al constructor de
estas clases el nombre de ste, luego con los mtodos read()
y write() actuaremos sobre l y finalmente mediante el
mtodo close() cerramos la sesin con el fichero. Ms
adelante se detallan un poco ms estas clases y las
acompaamos de algunos ejemplos tiles.
ADVERTENCIA: No confundir las dos clases anteriores con la
clase File. sta, para empezar, no trabaja sobre un flujo de
bytes sino que trata directamente con el fichero y con el
sistema de ficheros. Es decir, con esta clase no accedemos a
los datos de los ficheros, est orientada a obtener y/o
manipular la informacin asociada a ste como, por ejemplo,
permisos, fechas, si es un fichero o un directorio, el path,
etc... As cuando creamos una instancia de File, lo que
estamos haciendo es establecer un enlace con un archivo o
directorio fsico al que luego le podremos consultar todas sus
propiedades. Lo recomendable, para poder acceder a los
datos del fichero y a sus propiedades es crear una instancia a
la que le pasamos un objeto File de la siguiente manera:
El paquete java.io
Manejo de las I/O
File f = new File (ruta_del_fichero); instancia del descriptor
del fichero.
FileInputStream fis = new FileInputStream( f ); instancia de la
clase que nos permite leer los datos.
Ejemplo 3. Obtencin de las propiedades de un fichero.
/*
En este ejemplo presentamos algunos de los mtodos que la
clase File nos proporciona para conocer los detalles de un
fichero.
*/
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;

class FileDemo {
static void imprimir(String s) {
System.out.println(s);
}
public static void main(String args[]) {
File fich = new File("pon la ruta del fichero que quieras");
imprimir("Nombre del fichero : " + fich.getName());
imprimir("Path relativo : " + fich.getPath());
imprimir("Path Absoluto : " + fich.getAbsolutePath());
imprimir("Directorio padre : " + fich.getParent());
imprimir(fich.exists() ? "existe" : "no existe");
imprimir("Ultima modificacin del fichero : " +
fich.lastModified());
imprimir(fich.canWrite() ? "es de escritura" : "no es de
escritura");
imprimir(fich.canRead() ? "es de lectura" : "no es de lectura");
imprimir(fich.isFile() ? "fichero normal" : "no normal");
imprimir("Tamao del fichero : " + fich.length() + "Bytes");
try {
imprimir("URL del fichero : " +fich.toURL());
} catch (MalformedURLException urle)
{imprimir(urle.getMessage());}
fich.setReadOnly();//tambin podemos modificar sus atributos.
}
}//Fin clase FileDemo

Las clases orientadas a flujo de bytes


( Bytes Stream).
En apartados anteriores habamos discutido que en la cima de
la jerarqua de estas clases estaban las clases abstractas
InputStream y Outputstream. Vemos ahora las subclases
concretas ms importantes:
ByteArrayInputStream y ByteArrayOutputStream.
Implementan un flujo de entrada y salida de bytes
respectivamente teniendo como fuente un
array de bytes en el caso de la clase de entrada. En el caso de
la clase que maneja la salida
existen dos tipos de constructores: el 1 crea un buffer de 32
bytes y el 2 crea un buffer del

tamao que le digamos en el parmetro.


FileInputStream.
Como ya vimos, esta clase crea un InputStream que
usaremos para leer los bytes del fichero.
Define varios constructores de los cuales destacan el que le
pasamos como parmetro un
String que contiene la ruta completa del fichero y otro al que
le pasamos un objeto de tipo
File. En todos los casos, si el fichero no existe se debe lanzar
la excepcin
FileNotFoundException. La sintxis de los constructores ms
habituales es:
FileInputStream(String ruta_fichero);
FileInputStream(File fichero);//fichero es la descripcin del
archivo.
FileOutputStream.
Este, al contrario que el anterior crea un OutputStream para
enviar un flujo de bytes a un fichero. Igualmente al
constructor le podemos pasar la ruta completa del archivo o
un objeto de tipo File. Dado que esta operacin es de riesgo,
la clase puede lanzar una SecurityException. As mismo, se
pueden lanzar las excepciones IOException y/o
FileNotFoundException si, por ejemplo, el fichero no se
puede crear. La sintxis de los constructores ms habituales
es:
FileOutputStream(String ruta_fichero);
FileInputStream(File fichero);//fichero es la descripcin del
archivo.
IMPORTANTE: Si el fichero existe, cuando vayamos a escribir
sobre l, se borrar a menos que le digamos que aada los
datos al final de ste mediante el constructor
FileOutputStream(String filePath, boolean append), poniendo
append a true.
Antes de mostrarte algun ejemplo, veamos 1 los streams de
bytes filtrados para luego combinarlos en el ejemplo.

Las clases orientadas al filtrado del


flujo de bytes (Filtered Byte Stream).

Estas clases son simplemente wrappers de la entrada o salida


de los streams. Dichas clases proporcionan de manera
transparente a estos flujos una funcionalidad de un nivel
superior dado que las clases orientadas a flujo de bytes
quedan algo limitadas para "trabajar" sobre los datos leidos o
sobre los datos que vamos a escribir.
Lo que se hace es acceder al flujo de bytes por medio de
alguna de las clases o mtodos comentados en los apartados
anteriores
(normalmente
InputStream)
y,
luego,
se
"envuelven" con alguna de las clases orientadas a filtrarlos
para realizar operaciones algo ms complejas como, por
ejemplo, buferizar los datos, traslacin de caracteres o datos
crudos o, una de las ms importantes, convertir los bytes
leidos a alguno de los tipos primitivos de Java (byte, short, int,
etc...).
Las clases ms representativas de este tipo son
FilterInputStream y FilterOutputStream aunque a
continuacin pasar a explicar las ms tiles.
DataInputStream.
La importancia de esta clase radica en que nos permite
convertir la lectura de un flujo de bytes en uno de los tipos
primitivos que Java nos proporciona segn la forma que nos
interese
"empaquetar" esos bytes ledos. El nico constructor crea un
FilterInputStream y guarda el argumento que se le pasa para
usarlo
posteriormente.
Su
sintxis
es:
DataInputStream(InputStream in);
DataOutputStream.
Esta clase hace lo inverso de la anterior. Escribe a un flujo de
salida de bytes con alguno de los tipos de datos primitivos de
Java. La sintxis del constructor en este caso es:
DataOutputStream(OutputStream out);

BufferedInputStream.

Las clases orientadas a buferizar los flujos de bytes asignan


un buffer de memoria a los streams de I/O. Este buffer le
permite a Java realizar operacioes de I/O sobre ms de un
byte a la misma vez con lo que estas clases incrementan y
optimizan las prestaciones a la hora de trabajar con estos
datos de esta forma. Por tanto, esta clase nos permite
"envolver" cualquier InputStream en un stream buferizado
para optimizar el uso de la memoria. La sintxis de los dos
constructores que nos ofrece es:
BufferedInputStream (InputStream in);
BufferedInputStream (InputStream in, int bufSize);
La primera opcin crea un stream buferizado usando el
tamao por defecto del buffer mientras que la segunda opcin
usa un bufer del tamao indicado en bufSize. Una buena
eleccin de este tamao sera escoger un mltiplo aunque
sto depende de ciertos factores como el sistema operativo
sobre el que se ejecute, la cantidad de memoria disponible,
etc.
Una ltima observacin respecto a las clases orientadas a
buferizar datos es que implementan los mtodos mark() y
reset(), los cuales nos permiten acceder a datos del buffer ya
ledos. mark(int limite), como su nombre indica hace una
marca en el byte del stream sobre el que estemos situados en
ese momento. Con lmite indicamos el nmero de bytes que
tienen que transcurrir antes de dejar de tener efecto la marca
que hemos hecho.
reset(); al llamar a este mtodo, Java nos "reposiciona" en el
byte del stream sobre el que habamos hecho la marca.
BufferedOutputStream.
Esta clase es similar a OutputStream con la diferencia de que
incorpora el mtodo flush() con el cual aseguramos que los
datos en el buffer de salida son transferidos fsicamente al
dispositivo de escritura. En este mtodo es precisamente
donde radica la ventaja de esta clase frente a otras
destinadas a las escritura, reducir el nmero de veces que el
sistema realmente escribe sobre el dispositivo. La diferencia
es clara, no es lo mismo escribir byte a byte que enviar un
flujo de N bytes (tamao del buffer) de una tacada al

dispositivo. La sintxis de los constructores es similar al de la


clase anterior:
BufferedOutputStream (OutputStream in);
BufferedOutputStream (OuputStream in, int bufSize);

Las clases orientadas a flujo de


caracteres ( Character
Stream).

Aunque las clases orientadas al flujo de bytes nos


proporcionan la suficiente funcionalidad para realizar
cualquier tipo de operacin de entrada o salida, stas no
pueden trabajar directamente con caracteres Unicode. Es por
ello que fue necesario la creacin de las clases orientadas al
flujo de caracteres para ofrecernos el soporte necesario para
el tratamiento de caracteres.
Como ya dijimos al principio, estas clases nacen de las clases
abstractas Reader y Writer.
Las clases concretas derivadas de ellas tienen su homnimo
en las clases concretas derivadas de InputStream y
OutputStream, por tanto, la explicacin hecha para todas ellas
tiene validez para las orientadas a caracter salvo quizs
algunos
matices
que
podrs
completar
con
las
especificaciones por lo que omitiremos la explicacin
detallada de cada una de ellas.
No obstante, os dar una relacin de las clases ms
importantes. Son las siguientes:
1. Acceso a fichero: FileReader y FileWriter.
2. Acceso a caracter: CharArrayReader y CharArrayWriter.
3. Buferizacin de datos: BufferedReader y
BufferedWriter.

escribir datos

Leemos e escribimos
entrada/salida:

datos

del

flujo

estndar

de

System.out.println(Hello);
System.in.read();
Hasta ahora, para leer datos, utilizamos el paquete
TextIO:
TextIO.getlnChar();

Flujos estndares
Los flujos estndar de entrada y salida siempre estn
abiertos mientras se ejecuta el programa, listos para
proporcionar datos (entrada) o para acceptar datos (salida).
Por defecto, el flujo estndar de entrada es el teclado.
Referimos al flujo estndar de entrada con System.in
Por defecto, el flujo estndar de salida es la pantalla.
Referimos al flujo estndar de salida con System.out

int System.in.read()
Lee un cdigo ascii entre 0 y 255 (un byte) y lo pone en un
int. System.out.print(Introduzca caracter: ); char c =
(char)System.in.read();
System.out.println(\nIntroduciste
ReadCharacter.java

un:

c);

Podemos leer del flujo de entrada estndar tantos


caracteres como queremos, hasta encontrar eof (End Of File).
Al encontrar eof, System.in.read() devuelve -1.
Podemos simular eof dentro de una ventana cmd Windows
(dentro de Netbeans, no podemos). Para esto, entramos
Control-Z (en una nueva linea):
ReadCharacters1.java

Redirigir los flujos estndares


Podemos redirigir los flujos estndares de entrada y salida
para leer o escribir a un fichero. Por ejemplo, podemos entrar
desde la lnea de comandos (cmd):
java ReadCharacters1 < inputReadCharacters.txt
System.in
es
el
flujo
inputReadCharacters.txt

abierto

desde

el

fichero

Cada instruccin System.in.read() lee un carcter de este


fichero.
ReadCharacters1 lee el contenido de inputReadCharacters.txt,
hasta alcanzar eof. En este caso, no hace falta Control-Z, eof
occurre cuando se alcanza el final del fichero!
java ReadCharacters1 > outputReadCharacters.txt
System.out
es
el
outputReadCharacters.txt

flujo

abierto

al

fichero

Cada instruccin System.out.println escribe a este fichero


Si el fichero existe, el comando lo sobre-escribe (overwrite).
java ReadCharacters1 >> outputReadCharacters.txt
La instruccin >> redirige el flujo estndar de salida, pero sin
sobre-escribir el fichero si ya existe
java ReadCharacters1
outputReadCharacters.txt

<

inputReadCharacters.txt

Lee
de
inputReadCharacters.txt
outputReadCharacters.txt

escribe

>
a

Flujo (stream)
Un flujo, o stream, es una conexin entre un programa y una
fuente o destino de datos.
Un flujo de entrada maneja los datos que fluyen al programa
Un flujo de salida maneja los datos que fluyen del programa
En la figura, es un trozo de informacin
Ejemplo de aparatos de IO: conexin a internet, teclado,
ratn, pantalla, impresora, disco duro (es I y O, depende de la
aplicacin).

System.in
y
System.out
son
streams
creados
automaticamente cuando se ejecuta un programa Java.

Tipo de datos transmitidos por los


flujos
Con System.in.read( ), los trozos de informacin
transmitidos del teclado al programa son de tipo byte.

Problema: Como podemos leer otros datos como int o


double, que no caben en un byte? Como podemos leer
caracteres otros que ASCII (e.g., Unicode)?
Solucin: Necesitamos utilizar flujos de caracteres.
Nota: Tecnicamente, read() es un mtodo asociado con la
variable in, que es una variable de clase de System. La
variable in es de tipo InputStream, que permite manejar flujos
de entrada como bytes.

Flujos de bytes vs de caracteres


Existen dos tipos de flujos, flujos de bytes (byte streams) y
flujos de caracteres (carcter streams).
Los flujos de caracteres se usan para manipular datos
legibles por humanos (por ejemplo un fichero .txt).
Los flujos de bytes se usan para manipular datos binarios,
legibles solo por la maquina (por ejemplo un fichero .exe)

Flujos (Streams)
import java.io.*;
1. Abrir el stream
2. Usar el stream (leer, escribir)
3. Cerrar el stream

Cmo leer una lnea entera desde el


flujo de entrada estndar?
Cdigo completo: SystemIn.java

Se necesitan 3 flujos:
System.in de tipo InputStream lee Bytes desde el flujo de
entrada estndar.
InputStreamReader lee Bytes y les descodifica como
carcteres.
BufferedReader lee caracteres y les agrupa en lneas.
Flujo de carcteres BufferedReader:
Abre un flujo que lee desde un flujo de entrada de caracteres,
agrupa los caracteres a leer en un buffer (una zona de
memoria que sirve de tapn mientras se estn transmitiendo
los datos) , as permitiendo leer lineas enteras:
public String readLine() throws IOException
Creamos un flujo BufferedReader a partir de un flujo de
caracteres:
public BufferedReader(Reader in)

Cmo leer nmeros desde el flujo de


entrada estndar?
Hacemos como en en SystemIn.java, leemos lineas de
String, pero en bucle:
Leer 10 nmeros desde el flujo estndar y sumarlos:
SumarDiez.java

Leer N nmeros desde el flujo estndar y sumarlos (Ctrl-Z es


eof, que para String es null):
Sumar.java
Convertimos el String a int con: int Integer.parseInt (String
cadena)
Antes de convertir la cadena a un entero, tenemos que
eliminar la nueva lnea (\n). Para eso sirve trim(). Si no, la
conversin
fracasa
y
se
produce
una
excepcin:
java.lang.NumberFormatException.

Como leer un fichero


Para leer cualquier tipo de datos desde un archivo,
procedemos en dos etapas: crear un objeto de tipo FileReader
y luego un objeto de tipo BufferedReader.
FileReader: public
FileNotFoundException

FileReader(String

fileName)

throws

Establece un flujo de entrada para leer caracteres desde una


fuente externa (fichero). Los mtodos read de FileReader solo
leen un carcter o un trozo de un array de carcter.
Podemos leer lneas enteras de carcteres abriendo un flujo
de tipo BufferedReader a partir de un flujo de tipo FileReader.
Ejemplo: InStream.java

Como escribir a un fichero


FileWriter:
IOException

public

FileWriter(String

fileName)

throws

Abre un flujo de salida para escribir caracteres. Uno de sus


mtodos write (el de su super-clase Writer), puede imprimir un
String: public void write(String str) throws IOException

Ejemplo: OutStream.java
char Unicode, 16 bits

byte, 8 bits.

Reader y Writer son las clases bases de la jerarqua para los


flujos de caracteres. Para leer o escribir datos binarios tales
como imgenes o sonidos, se emplea otra jerarqua 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 mtodos para leer un
carcter char o un array de caracteres
int read()
int read(char buf[])
int read(char buf[], int offset, int len)

InputStream proporciona mtodos similares para leer un byte


o un array de bytes.
int read()
int read(byte buf[])
int read(byte buf[], int offset, int len)
La primera versin lee un byte como entero del flujo de
entrada, devuelve 1 si no hay ms datos que leer. La
segunda versin, lee un array de bytes devolviendo el nmero
de bytes ledos. La tercera versin, lee tambin, un array de
bytes, pero nos permite especificar, la posicin de comienzo
del array en la que se empiezan a guardar los bytes, y el
mximo nmero de bytes que se van a leer.
Dichas clases definen otras funciones miembro que no
estudiaremos de momento.
Escritura
La clase Writer proporciona tres mtodos para escribir un
carcter char o un array de caracteres
int write(int c)
int write(char buf[])
int write(char buf[], int offset, int len)
La clase OutputStream proporciona mtodos similares
int write(int c)
int write(byte buf[])
int write(byte buf[], int offset, int len)
Integrantes:
Tania Ramos
Ovidio Durango