En esta sesión practicaremos algunos conceptos básicos de Entrada/Salida, como la lectura y escritura básica con ficheros, y el uso de ficheros de propiedades, y entrada/salida estándar. Antes de comenzar, lee la introducción del punto 2.3 (Entrada/Salida), y los apartados 2.3.1 (Flujos de Entrada/Salida), 2.3.2 (Entrada, salida y salida de error estándar) y 2.3.3 (Acceso a ficheros) del tema 2 de teoría.
1. En este primer ejercicio practicaremos la lectura y escritura básica con ficheros, utilizando las dos posibles alternativas: Streams y Readers/Writers:
public void leeEscribeStream() { FileInputStream in = new FileInputStream("entrada.dat"); }
public void leeEscribeStream() { FileInputStream in = new FileInputStream("entrada.dat"); FileOutputStream out = new FileOutputStream("salidaStream.dat"); }
public void leeEscribeStream() { FileInputStream in = new FileInputStream("entrada.dat"); FileOutputStream out = new FileOutputStream("salidaStream.dat"); int c; while ((c = in.read()) != -1) { out.write(c); } }
Echa un vistazo a la documentación sobre el método read. ¿Por
qué se compara el dato que se lee con -1?
public void leeEscribeStream() { ... in.close(); out.close(); }
public void leeEscribeStream() { try { ... } catch (FileNotFoundException e) { Sytem.err.println ("Fichero no encontrado"); } catch (IOException e2) { System.err.println ("Error al acceder a los ficheros"); } }
Captúralas y prueba el resultado.
public void leeEscribeStream() { try { FileInputStream in = new FileInputStream("entrada.dat"); FileOutputStream out = new FileOutputStream("salidaStream.dat"); byte[] b = cabecera.getBytes(); out.write(b); int c; while ((c = in.read()) != -1) ... }
Prueba el método ya completo, y comprueba que el fichero de salida (salidaStream.dat) deja algo como:
# Esto es la cabecera del fichero que hay que introducir Hola, este es el texto del fichero de entrada que debería copiarse en el fichero de salida
public void leeEscribeWriter() { BufferedReader br = new BufferedReader(new FileReader("entrada.dat")); PrintWriter pw = new PrintWriter(new FileWriter("salidaWriter.dat")); }
Observad que para construir tanto el BufferedReader como el PritWriter
nos valemos de un objeto FileReader o FileWriter,
respectivamente. Lo que hacemos es simplemente crear un buffer de
entrada (BufferedReader) o de salida (PrintWriter) sobre
el FileReader o el FileWriter para poder acumular cadenas
de texto enteras antes de leerlas o escribirlas.
public void leeEscribeWriter() { BufferedReader br = new ...; PrintWriter pw = new ...; String linea = ""; while ((linea = br.readLine()) != null) { pw.println(linea); } }
El uso de PrintWriter permite formatear la salida de la misma
forma que si la estuviésemos sacando por pantalla, puesto que tiene los
mismos métodos que el campo System.out (métodos println,
print, etc).
Echa un vistazo a la documentación sobre el método readLinea. ¿Por
qué se compara el dato que se lee con null?
public void leeEscribeWriter() { ... br.close(); pw.close(); }
public void leeEscribeWriter() { try { ... } catch (FileNotFoundException e) { Sytem.err.println ("Fichero no encontrado"); } catch (IOException e2) { System.err.println ("Error al acceder a los ficheros"); } }
Captúralas y prueba el resultado.
public void leeEscribeWriter() { try { BufferedReader br = ...; PrintWriter pw = ...; pw.print(cabecera); String linea = ""; while ((linea = br.readLine()) != null) ... }
Prueba el método ya completo, y comprueba que el fichero de salida (salidaWriter.dat)
deja el mismo resultado que con el método anterior.
2. En este segundo ejercicio practicaremos el uso de ficheros de propiedades, y el uso de la entrada y salida estándares.
public Ej5() { Properties p = new Properties(); p.load(new FileInputStream("prop.txt")); }Observa que para cargar las propiedades, al método load le debemos pasar un InputStream desde el que leerlas. En este caso le pasamos un FileInputStream con el fichero prop.txt.
public Ej5() { Properties p = new Properties(); p.load(new FileInputStream("prop.txt")); Enumeration en = p.propertyNames(); while (en.hasMoreElements()) { String prop = (String)(en.nextElement()); System.out.println("Introduzca valor para propiedad " + prop); } }
Observa el orden en que van mostrándose las propiedades. ¿Es el mismo que el que hay en el fichero? ¿A qué crees que puede deberse? (AYUDA: cuando nosotros enumeramos una serie de características, no tenemos que seguir un orden necesariamente. Del mismo modo, cuando introducimos valores en una tabla hash, el orden en que se guardan no es el mismo que el orden en que los introducimos).
Lo que hacemos con este bucle es sólo recorrer los nombres de las propiedades y sacarlos por pantalla. Nos falta hacer que el usuario teclee los valores correspondientes. Para ello utilizaremos un objeto de tipo BufferedReader, que en este caso leerá líneas de texto que el usuario entre desde teclado:
public Ej5() { Properties p = new Properties(); p.load(new FileInputStream("prop.txt")); Enumeration en = p.propertyNames(); BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); while (en.hasMoreElements()) { ... } }
observad que construimos el BufferedReader para leer de un InputStream
(no de un Reader). Esto lo podemos hacer si nos ayudamos de la
"clase puente" InputStreamReader, que transforma un tipo
de lector en otro.
Lo que nos queda por hacer es pedirle al usuario que, para cada nombre de
propiedad, introduzca su valor, y luego asignarlo a la propiedad
correspondiente:
public Ej5() { ... while (en.hasMoreElements()) { String prop = (String)(en.nextElement()); System.out.println("Introduzca valor para propiedad " + prop); String valor = in.readLine(); p.setProperty(prop, valor); } }
Finalmente, cerramos el buffer de entrada, y guardamos las propiedades en el fichero.
public Ej5() { ... in.close(); p.store(new FileOutputStream("prop.txt"), "Cabecera del fichero"); }
Compilad y ejecutad el programa. Para que os compile deberéis capturar las excepciones que se os indique en los errores de compilación:
public Ej5() { try { ... } catch(...) {} }
PARA ENTREGAR