Anda di halaman 1dari 12

Entrada y Salida en Java

Introducción
Desde el inicio del curso hemos realizado operaciones de entrada y salida en Java, desde leer
un carácter que un usuario introduce por teclado hasta utilizar los métodos System.out.print()
y System.out.println() para imprimir datos en pantalla, en este capítulo veremos con más
detenimiento como funciona la entrada salida utilizando para ello el paquete java.io.

Para entender como funcionan las distintas clases del paquete java.io deberemos antes
comprender algunos conceptos básicos.

Flujos: Un flujo es una abstracción de una entidad que produce o consume datos. Un flujo se
debe vincular a un dispositivo físico para que pueda realizar su labor (por ejemplo un flujo de
entrada a la consola para poder obtener datos que introduzca el usuario).

Una particularidad de los flujos en java es que todos utilizan los mismos métodos y que se
pueden aplicar las mismas clases independientemente del dispositivo al que esté conectado,
es decir una misma clase puede utilizarse tanto para leer de un fichero como para leer de
consola.

Otro concepto a tener en cuenta son los tipos de flujo, podemos diferenciar dos tipos, según el
tipo de datos que producen o consumen:

Flujos de bytes: Permite la lectura de bytes para la lectura y escritura de datos


binarios.

Flujos de caracteres: Permiten realizar lectura/escritura mediante caracteres,


siendo especialmente útiles al trabajar con archivos.

Como hemos visto, Java posee flujos ya definidos en la librería java.io, por ejemplo in para
flujo de entrada estándar, out para flujo de salida estándar y err como flujo de error estándar,
dichos flujos por defecto se encuentra vinculados al teclado in y a la consola tanto out como
err.
La clase File
Antes de abordar el uso de los flujos para entrada y salida veamos brevemente una clase de
utilidad como es la clase File.

La clase File permite representar un fichero mediante un objeto, pudiendo realizar así
operaciones sobre él como por ejemplo conocer si un fichero existe, su tamaño, etc…

Para la lectura y escritura en ficheros utilizaremos flujos de datos, pero de momento


quedémonos con el siguiente ejemplo:

String nombreFich="File.txt";
fichero=new File(nombreFich);
if (fichero.exists()){
System.out.println("El fichero existe");
}
else{
try{
fichero.createNewFile();
System.out.println("¡¡ El fichero se creó con éxito !!");
}
catch (IOException exc){
System.out.println("Hubo un problema");
}
}

En este ejemplo se comprueba que el fichero cuyo nombre almacenamos en nombreFich


existe previamente en el directorio actual, en caso de no existir crea dicho fichero.

¿Cómo lo realiza?

En primer momento se crea un objeto de tipo java.io.File utilizando para ello el nombre de
fichero almacenada en la variable String nombreFich.

Posteriormente llamando al método exists del objeto File comprobamos si el fichero existe
mediante el if inicial.

Si se cumple la condición de que exista lanzamos un mensaje a consola indicando que existe el
fichero.

Si no se cumple la condición de existencia, entraríamos en el cuerpo del else donde creamos el


fichero.

Como podemos comprobar, el cuerpo del else contrala que en la operación de creación de
fichero no haya ningún problema, es decir que no se produzca una excepción de
entrada/salida (IOException) y en caso de producirse generamos un mensaje de error al
usuario.
Entrada/Salida Binaria mediante flujos de bytes

Cuando utilizamos flujos de bytes utilizaremos cadenas de bytes para leer/escribir utilizando el
flujo, en la parte superior de la jerarquía de clases de estos flujos se encuentran las clases
InputStream y OutputStream. Deberemos tener en cuenta que los métodos de estas clases
pueden generar una IOException en caso de que se dé un error de lectura o escritura.

Los flujos de Bytes tienen como clases padre las clase InputStream y OutputStream, las cuales
son clases abstractas.

InputStream define las características de las clases de entrada mientras que OutputStream
define las de las clases de salida.

Todas las clases de Entrada/Salida mediante flujo de bytes se nombran utilizando en su


nombre de clase InputStream o OutputStream.

Podemos destacar varias como por ejemplo BufferedInputStream y BufferedOutputStream


que implementan un buffer interno para acelerar las trasferencias de datos.

Otras dos clases a destacar son DataInputStream y DataOutputStream que permiten leer y
escribir los tipos primitivos de java.

Entrada/Salida mediante Caracteres


Para E/S mediante caracteres tenemos las clases principales Reader y Writer.

Todas las clases de E/S mediante caracteres tienen en su nombre Reader o Writer.

Al igual que las clases basadas en bytes generan en caso de erro una IOException.

Veamos algunas de las mas destacadas.

Al igual que en las orientadas a bytes tenemos clases BufferedReader y BufferedReader que
implementan un buffer interno para mejorar el rendimiento.

FileReader y FileWriter se utilizarán para leer/Escribir de fichero.

Flujos ya definidos en Java.


Aunque no eramos conscientes, llevamos utilizando E/S desde que ejecutamos la primera
instrucción System.out.println()… ¡¡¡ Que tiempos aquellos ¡!! no???.

Java define 3 flujos:

• Entrada estándar: Por defecto el teclado, su clase es java.io.BufferedInputStream.


• Salida estándar: Por defecto la consola, System.out su clase es java.io.PrintStream.
• Error estándar: El error por defecto, su clase es java.io.PrintStream.

Podemos usar estos flujos para crear nuevos objetos flujo de E/S.
Usar Flujos de Bytes
Para usar flujos de bytes utilizaresmo los métodos definidos por las clases InputStream y
OutputStream.

Los principales métodos son read, write y close, otros métodos disponibles además son :
Usar Flujos de caracteres

Como hemos determinado, en la salida de caracteres se utilizan las clases Reader y Writer.

Sin embargo estas clases no son las más utilizadas como veremos posteriormente.
Al comienzo Java no contemplaba la lectura/Escritura mediante caracteres, todo se realizaba
mediante flujo de bytes. Por ello surgieron las clases InputStreamReader e InputStreamWriter
que nos permiten leer y escribir basándonos en caracteres sobre flujos basados en bytes.

Para ello creamos un objeto de estas clases a partir de uno de tipo InputStream o
OutputStream. ¿ algo lioso? , pues sí que le vamos a hacer…

Veamos como leer un carácter por consola, para ello utilizaremos la clase BufferedReader.

Si miramos sus constructores, vemos que necesitamos un objeto de tipo Reader para poder
crear nuestro objeto, teniendo en cuenta que la consola (System.in en este caso) es un objeto
de tipo BufferedInputStream, no podemos crear nuestro objeto. :’(

Constructores de BufferedInputStream
public BufferedReader(Reader in, int sz)

public BufferedReader(Reader in)

Para solucionarloInputStreamReader al rescate, veámoslo con un ejemplo:

import java.io.*;

char car = 0;

BufferedReader entrada=new BufferedReader(new InputStreamReader(System.in));

try{

//Por defecto read() devuelve un caracter entero

// que representa al caracter deberemos hacer un casting

car=(char) entrada.read();

catch (IOException exc){

System.out.println("\n Error: se ha producido un error al leer. ");

Código 1:Leer Char

¿Como leeríamos un String?


String cad="";

BufferedReader entrada=new BufferedReader(new InputStreamReader(System.in));

try{

cad=entrada.readLine();

catch(IOException exc){

System.out.println("\n Error: se ha producido un error al leer.”);

Código 2:Leer String

¿Como hemos visto hemos podido leer una cadena y un String mediante read y readLine,
como leeríamos el resto de tipos básicos?

Facil, aprovechamos las clases contenedoras Integer, Double…etc y llamamos a los métodos
parseInt…

Por ejemplo para leer un entero desde consola:

int numero=0;

String cad="";

BufferedReader entrada=new BufferedReader(new InputStreamReader(System.in));

try{

cad=entrada.readLine();

numero=Integer.parseInt(cadena);

catch (Exception exc){

//Pueden darse IOException o NumberFormatException si no es un numero.

System.out.println(" Error: se ha producido un error al leer.”);

Código 3: Leer int


Nota sobre los ejemplos y la clase Persona
En estos ejemplos utilizaremos una clase denominada persona que posee los siguientes
atributos:

id: int

nombre: String

apellido1:String

apellido2:String

En dicha clase también se encuentra inplementado el método toString() que devuelve una
representación de String del objeto.

Lectura desde un fichero mediante caracteres:


Bueno ya sabemos leer y escribir desde teclado ¿Cuándo empezamos con los ficheros?

Facil, en 1 linea:

En un fichero podemos leer y escribir de la misma manera que lo hemos hecho con los flujos
de consola, tan solo deberemos utilizar las clases File adecuadas dependiendo de si queremos
escribir/leer caracteres o bytes.

Para Leer de un fichero mediante Caracteres:

Para leer de un fichero mediante caracteres deberemos utilizar FileReader, para crearlo la
manera más sencilla es usar uno de los siguientes dos constructores:

FileReader(File file)

FileReader(String fileName)

Mediante el primero creamos el objeto a través de un objeto File, mediante el segundo le


pasamos la ruta al fichero.

Sin embargo mediante esta clase tan solo podremos ir leyendo carácter a carácter lo cual
puede llegar a ser tedioso, en nuestro caso supongamos que almacenamos cada dato en una
línea.

¿Cómo leemos líneas enteras?, fácil creando un objeto BufferedReader a partir de nuestro
FileReader y leyendo de este, ya que esta clase nos ofrece el método readLine().
Veamos como quedaría nuestro ejemplo:

//Para E/S con caracter


FileReader fichEntrada2;
BufferedReader bufFichEntrada2;

//Voy a Leer los datos de una persona mediante Escritura de Caracteres


perso2=new Persona();
fichEntrada2=new FileReader(fichero);
bufFichEntrada2=new BufferedReader(fichEntrada2);
perso2.setId(Integer.parseInt(bufFichEntrada2.readLine()));
perso2.setNombre(bufFichEntrada2.readLine());
perso2.setApellido1(bufFichEntrada2.readLine());
perso2.setApellido2(bufFichEntrada2.readLine());
bufFichEntrada2.close();
fichEntrada2.close();

System.out.println("Hemos leido mediante caracteres la persona:


"+perso2.toString());
}
catch(IOException e){
System.out.println("Hubo un problema de E/S: "+e.getMessage());
}
Escritura a Fichero mediante Caracteres:
En cuanto a la escritura es aún mas simple, tan solo deberemos usar el método write que nos
escribe una cadena de caracteres en el fichero.

Para ello creamos un objeto FileReader y pasamos a utilizarlo, veámoslo con un ejemplo:

//Voy a Escribir los datos de una persona mediante Escritura de Caracteres

fichero=new File("Miguel_Car.txt");

try{

//Puedo poner el segundo parametro a true para usar un constructor que añada al fichero

fichsalida2=new FileWriter(fichero);

fichsalida2.write(Integer.toString(perso1.getId()));

fichsalida2.write("\n");

fichsalida2.write(perso1.getNombre());

fichsalida2.write("\n");

fichsalida2.write(perso1.getApellido1());

fichsalida2.write("\n");

fichsalida2.write(perso1.getApellido2());

fichsalida2.write("\n");

fichsalida2.close();

catch (IOException e){

System.out.println("Ha ocurrido un error.");

}
Lectura a fichero mediante Bytes
Para Realizar la lectura de un fichero mediante bytes , para ello si no deseo complicarme
demasiado la vida puedo escribir directamente los tipos primitivos mediante la clase
DataInputStream, que nos ofrece métodos específicos para cada tipo que deseemos leer.

Primeramente creamos un FileInputStream y a partir de él crearemos nuestro


DataInputStream.

Veamos un ejemplo:

FileInputStream fichEntrada;
DataInputStream leer;
File fichero =new File("Miguel.txt");
Persona perso1,perso2;
fichero=new File("Miguel.txt");
try{
fichEntrada=new FileInputStream(fichero);
leer=new DataInputStream(fichEntrada);
perso2=new Persona();

perso2.setId(leer.readInt());
perso2.setNombre(leer.readUTF());
perso2.setApellido1(leer.readUTF());
perso2.setApellido2(leer.readUTF());
leer.close();
fichEntrada.close();
System.out.println("Hemos leido mediante Bytes: +perso2.toString());
}
catch(IOException e){
System.out.println("Hubo un problema de E/S: "+e.getMessage());
}
Escritura a fichero mediante Bytes
Al igual que con la lectura de fichero utilizaremos la clase DataOutputStream que nos facilitará
bastante el trabajo.

Primeramente creamos un FileOutputStream y a partir de él crearemos nuestro


DataOutputStream.

Veamos un ejemplo:

//Para E/S de Bytes.


FileOutputStream fichSalida;
DataOutputStream escribir;
File fichero =new File("Miguel.txt");
Persona perso1,perso2;

fichero=new File("Miguel.txt");

try{
if (!fichero.exists()){
fichero.createNewFile();
}
// Voy a escribir los datos de una persona mediante escritura de Bytes.
fichSalida=new FileOutputStream(fichero);
escribir=new DataOutputStream(fichSalida);
escribir.writeInt(perso1.getId());
escribir.writeUTF(perso1.getNombre());
escribir.writeUTF(perso1.getApellido1());
escribir.writeUTF(perso1.getApellido2());
escribir.close();
System.out.println("Hemos escrito mediante Bytes:
"+escribir.size()+"Bytes");
fichSalida.close();
}
catch(IOException e){
System.out.println("Hubo un problema de E/S: "+e.getMessage());
}

Nota final: Apuntes aún sin finalizar, tan solo para poder verlo en clase.