Diferencia entre revisiones de «Prog. Ficheros»
Ir a la navegación
Ir a la búsqueda
Imagen obtenida de los apuntes de Jose Luis Comesaña
| Línea 1: | Línea 1: | ||
| − | = | + | =Entrada/Salida de información: Flujos= |
* Este punto sólo sirve de apoyo y para realizar ejercicios, a los apuntes de Jose Luis Comesaña. | * Este punto sólo sirve de apoyo y para realizar ejercicios, a los apuntes de Jose Luis Comesaña. | ||
| Línea 127: | Línea 127: | ||
| + | <br /> | ||
| + | =Clases para lectura de caracteres= | ||
| + | * Veamos ahora todas las clases de lectura de caracteres. | ||
| + | : Como norma general debemos de tener en cuenta que los Reader van a permitir leer caracteres en base a alguna codificación y nos van a suministrar caracteres, mientras que los Stream van a leer bytes que tendremos que convertir a caracteres. | ||
| + | :* [https://docs.oracle.com/javase/7/docs/api/java/io/BufferedReader.html BufferedReader]: Permite leer texto sobre un flujo de texto pero haciendo uso de un buffer intermedio haciendo que el rendimiento aumente. | ||
| + | :* [https://docs.oracle.com/javase/7/docs/api/java/io/CharArrayReader.html CharacterArrayReader]: Permite leer caracteres sobre un flujo de caracteres. | ||
| + | :* [https://docs.oracle.com/javase/7/docs/api/java/io/InputStreamReader.html InputStreamReader]: Permite leer un flujo de bytes convirtiéndolo a un flujo de caracteres, pudiendo especificar el juego de caracteres utilizado en la conversión. | ||
| + | :* [https://docs.oracle.com/javase/7/docs/api/java/io/StringReader.html StringReader]: Un flujo de caracteres cuyo origen es un String. ¿ Y para qué puede servir esto ? | ||
| + | :: Pues en el caso de que necesitéis pasar a un componente un Reader. Por ejemplo, a la clase StreamTokenizer que veremos más adelante. | ||
| + | :* [https://docs.oracle.com/javase/7/docs/api/java/io/PipedReader.html PipedReader]: Permite una comunicación entre una 'tubería' de entrada y otra de salida. En Java se suele utilizar para comunicar dos threads dentro del mismo programa, en el que uno de ellos escribe en una tubería (PipedWriter) y otro lee el contenido de la misma (PipedReader) en forma de caracteres. | ||
| + | :: Sus equivalentes leyendo y escribiendo bytes son PipedInputStream y PipedOutputStream. | ||
| + | :: Podéis consultar un ejemplo de uso en [http://tutorials.jenkov.com/java-io/pipes.html este enlace]. | ||
| + | :* [https://docs.oracle.com/javase/7/docs/api/java/io/PushbackReader.html PushbackReader]: La clase FilterReader es abstracta y por tanto no se puede instanciar. La clase PushbackReader deriva de ella y es una clase que permite lectura de caracteres y además permite volver a 'meter' esos caracteres en el stream para volver a leerlos. Esto puede ser necesario si necesitamos leer un contenido de un fichero para determinar que tipo de contenido trae y después tratarlo en función de ese tipo de contenido. Para ello debemos de leer (método read) caracteres y después tendremos que volver a leerlos por lo que tendremos que llamar al [https://docs.oracle.com/javase/7/docs/api/java/io/PushbackReader.html#unread%28char[]%29 método unread]. | ||
| + | :* [https://docs.oracle.com/javase/7/docs/api/java/io/LineNumberReader.html LineNumberReader]: Lee caracteres y permite 'saltar' a una línea determinada llamando al [https://docs.oracle.com/javase/7/docs/api/java/io/LineNumberReader.html#setLineNumber%28int%29 método setLineNumber]. | ||
| + | |||
| + | :* [https://docs.oracle.com/javase/7/docs/api/java/io/StreamTokenizer.html StreamTokenizer]: Permite dividir un flujo de entrada en 'tokens' pudiendo reconocer palabras, números, identificadores, ciertos estilos de comentarios,... | ||
| + | |||
| + | |||
| + | <br /> | ||
| + | ==Ejercicios propuestos== | ||
| + | |||
| + | |||
| + | * Crea una clase de nombre TratamientoFicheros que conste de los siguientes métodos (no necesita instanciarse la clase para poder llamar a dichos métodos): | ||
| + | |||
| + | :* leerFichero(String nombre): devolverá un string con los datos del fichero leído. | ||
| + | :: Debes hacer uso de la clase | ||
| + | <br /> | ||
| + | =Entrada/Salida estándar= | ||
* Utilizando los conceptos vistos de salida y entrada estándar podemos hacer una redirección de la salida estándar (podríamos hacerlo con la salida de errores o la entrada estándar) a un fichero. | * Utilizando los conceptos vistos de salida y entrada estándar podemos hacer una redirección de la salida estándar (podríamos hacerlo con la salida de errores o la entrada estándar) a un fichero. | ||
: Para ello debemos hacer uso del [https://docs.oracle.com/javase/7/docs/api/java/lang/System.html#setOut(java.io.PrintStream) método setOut()] de la clase System. | : Para ello debemos hacer uso del [https://docs.oracle.com/javase/7/docs/api/java/lang/System.html#setOut(java.io.PrintStream) método setOut()] de la clase System. | ||
| Línea 167: | Línea 195: | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
Revisión del 09:02 16 ene 2018
Sumario
Entrada/Salida de información: Flujos
- Este punto sólo sirve de apoyo y para realizar ejercicios, a los apuntes de Jose Luis Comesaña.
- En java, para entender el sistema de entrada/salida de información (es decir, como leer o escribir información desde o hacia cualquier dispositivo), es necesario entender el concepto de flujo.
- Podemos definir flujo como una 'abstracción' que proporciona Java y que identifica a una secuencia de bytes desde un dispositivo de entrada hacia un dispositivo de salida.
- A través de dichos flujos vamos a poder realizar lecturas y escrituras sobre diferentes dispositivos sin que el programador necesita saber nada acerca de ellos, ya que será el núcleo de Java el que se entenderá con el S.O. para realizar las operaciones correspondientes.
- En Java, dichos flujos están identificados por una jerarquía de clases que se encuentran en el paquete java.io:
- Podemos dividir estas clases en dos grupos, en función del tipo de dato que van a leer:
- Clases que leen o escriben flujos de caracteres de 16 bits unicode. Estas son las clases abstractas Reader y Writer y todas las que deriven de ellas.
- Clases que leen o escriben flujo de bytes de 8 bits. Estas son las clases abstractas InputStream y OutputStream y todas las que deriven de ellas.
- Quizás podemos entender más claramente el concepto de flujo si nos fijamos cuando escribimos por teclado y desde nuestro programa guardamos dicha información o cuando mandamos escribir por consola un texto determinado.
- En Java, las letras (información) que estamos tecleando llegan a nuestro programa a través de un 'flujo' de entrada, denominado 'flujo de entrada estándar' y posteriormente enviamos información a la consola a través de un 'flujo de salida estándar'. En caso de encontrar algún error también enviará un mensaje a la consola (como la salida) por medio de otro flujo de datos.
- Estos flujos en Java los tenemos implementados en los objetos System.in, System.out y System.err.
- Si observáis la definición de dichos objetos (son final y de clase) veréis que pertenecen a alguna de las clases de la jerarquía anterior.
- Bufferes (información obtenida de estos apuntes).
- En la jerarquía anterior vemos que hay ciertas clases que implementan un buffer (BufferedReader, BufferedInputStream,...).
- Recordar que un buffer es una zona de almacenamiento, que se utiliza de 'puente' entre un dispositivo de entrada y otro de salida, para aumentar la velocidad en las operaciones de lectura y escritura así como el rendimiento.
- Si usamos sólo FileInputStream, FileOuputStream, FileReader o FileWriter, cada vez que hagamos una lectura o escritura, se hará físicamente en el disco duro.
- Si escribimos o leemos pocos caracteres cada vez, el proceso se hace costoso y lento, con muchos accesos a disco duro.
- Los BufferedReader, BufferedInputStream, BufferedWriter y BufferedOutputStream añaden un buffer intermedio.
- Cuando leamos o escribamos, esta clase controlará los accesos a disco.
- Si vamos escribiendo, se guardarán los datos hasta que tenga bastantes datos como para hacer la escritura eficiente.
- Si queremos leer, la clase leerá muchos datos de golpe, aunque sólo nos dé los que hayamos pedido. En las siguientes lecturas nos dará lo que tiene almacenado, hasta que necesite leer otra vez.
- Esta forma de trabajar hace los accesos a disco más eficientes y el programa correrá más rápido. La diferencia se notará más cuanto mayor sea el fichero que queremos leer o escribir.
- Veamos un sencillo ejemplo de cómo leer un archivo de texto.
- Para ello, debemos hacer uso de la clase FileReader, que como comentamos antes, es una clase que sirve para leer caracteres.
- Incorpora por tanto el método read.
- Para leer un archivo siempre vamos a tener que realizar las siguientes operaciones:
- Abrir el archivo para iniciar la lectura.
- Leer del archivo hasta llegar al final del mismo.
- Cerrar el archivo.
- En nuestro caso, debemos crear un objeto de la clase FileReader, en el que podemos observar como el constructor está sobrecargado, y en uno de ellos debemos enviar un String con la ruta y nombre del fichero a abrir.
- Al llamar al constructor ya nos abre el fichero para iniciar la lectura.
- Después debemos leer del fichero carácter a carácter utilizando el método read() hasta el final del mismo. Esto lo sabemos ya que el método read() devuelve el valor -1 cuando llega al final.
- Finalmente debemos cerrar el fichero con el método close().
- Puede suceder que tengamos excepciones debido a que el fichero no exista o no se pueda leer o que durante el proceso de lectura dejemos de tener acceso al mismo (FileNotFoundException y IOException).
1 FileReader f = null; 2 int c; 3 4 try { 5 f = new FileReader("/tmp/prueba.txt"); 6 while((c = f.read())!=-1) { 7 System.out.print((char)c); 8 } 9 10 11 } catch (FileNotFoundException ex) { 12 System.err.println("Fichero no encontrado"); 13 } catch (IOException ex) { 14 System.err.println("Error al leer el contenido del fichero"); 15 } 16 finally { 17 try { 18 if (f != null) 19 f.close(); 20 } catch (IOException ex) { 21 System.err.println("Error al leer cerrar fichero"); 22 } 23 }
- Indicar que a partir del JDK 7 podemos hacer uso de un nuevo recurso denominado try-with-resources.
- Es una forma 'especial' de utilizar el try de tal forma que el cierre del flujo ya se realiza automaticamente tanto si todo se ejecuta de forma correcto como si hay una excepción y ya no tenemos que realizar una llamada a close(). Esto se puede hacer con cualquier objeto que implemente la interface AutoClosable.
1 int c; 2 3 try (FileReader f = new FileReader("/tmp/prueba.txt"){ 4 while((c = f.read())!=-1) { 5 System.out.print((char)c); 6 } 7 8 9 } catch (FileNotFoundException ex) { 10 System.err.println("Fichero no encontrado"); 11 } catch (IOException ex) { 12 System.err.println("Error al leer el contenido del fichero"); 13 }
- Indicar que la definición del objeto debe ir dentro del try y entre paréntesis (en el ejemplo FileReader f...).
- Si tenemos varios recursos, es mejor instanciarlos separadamente y separarlos con punto y coma, como por ejemplo:
1 String filePath = "/tmp/fichero.txt"; 2 int bsize = 1024; /* tamaño del buffer */ 3 4 try (FileReader file = new FileReader(filePath); 5 BufferedReader br = new BufferedReader(file, bsize)) 6 { 7 return read(br); 8 }
Clases para lectura de caracteres
- Veamos ahora todas las clases de lectura de caracteres.
- Como norma general debemos de tener en cuenta que los Reader van a permitir leer caracteres en base a alguna codificación y nos van a suministrar caracteres, mientras que los Stream van a leer bytes que tendremos que convertir a caracteres.
- BufferedReader: Permite leer texto sobre un flujo de texto pero haciendo uso de un buffer intermedio haciendo que el rendimiento aumente.
- CharacterArrayReader: Permite leer caracteres sobre un flujo de caracteres.
- InputStreamReader: Permite leer un flujo de bytes convirtiéndolo a un flujo de caracteres, pudiendo especificar el juego de caracteres utilizado en la conversión.
- StringReader: Un flujo de caracteres cuyo origen es un String. ¿ Y para qué puede servir esto ?
- Pues en el caso de que necesitéis pasar a un componente un Reader. Por ejemplo, a la clase StreamTokenizer que veremos más adelante.
- PipedReader: Permite una comunicación entre una 'tubería' de entrada y otra de salida. En Java se suele utilizar para comunicar dos threads dentro del mismo programa, en el que uno de ellos escribe en una tubería (PipedWriter) y otro lee el contenido de la misma (PipedReader) en forma de caracteres.
- Sus equivalentes leyendo y escribiendo bytes son PipedInputStream y PipedOutputStream.
- Podéis consultar un ejemplo de uso en este enlace.
- PushbackReader: La clase FilterReader es abstracta y por tanto no se puede instanciar. La clase PushbackReader deriva de ella y es una clase que permite lectura de caracteres y además permite volver a 'meter' esos caracteres en el stream para volver a leerlos. Esto puede ser necesario si necesitamos leer un contenido de un fichero para determinar que tipo de contenido trae y después tratarlo en función de ese tipo de contenido. Para ello debemos de leer (método read) caracteres y después tendremos que volver a leerlos por lo que tendremos que llamar al [%29 método unread].
- LineNumberReader: Lee caracteres y permite 'saltar' a una línea determinada llamando al método setLineNumber.
- StreamTokenizer: Permite dividir un flujo de entrada en 'tokens' pudiendo reconocer palabras, números, identificadores, ciertos estilos de comentarios,...
Ejercicios propuestos
- Crea una clase de nombre TratamientoFicheros que conste de los siguientes métodos (no necesita instanciarse la clase para poder llamar a dichos métodos):
- leerFichero(String nombre): devolverá un string con los datos del fichero leído.
- Debes hacer uso de la clase
Entrada/Salida estándar
- Utilizando los conceptos vistos de salida y entrada estándar podemos hacer una redirección de la salida estándar (podríamos hacerlo con la salida de errores o la entrada estándar) a un fichero.
- Para ello debemos hacer uso del método setOut() de la clase System.
1 FileReader f = null; 2 int c; 3 PrintStream pStreamSalida=null; 4 5 try { 6 pStreamSalida = new PrintStream("/tmp/salida.txt"); 7 System.setOut(pStreamSalida); 8 f = new FileReader("/tmp/prueba.txt"); 9 while((c = f.read())!=-1) { 10 System.out.print((char)c); 11 } 12 13 14 } catch (FileNotFoundException ex) { 15 System.err.println("Fichero no encontrado"); 16 } catch (IOException ex) { 17 System.err.println("Error al leer el contenido del fichero"); 18 } 19 finally { 20 try { 21 if (f != null) 22 f.close(); 23 } catch (IOException ex) { 24 System.err.println("Error al leer cerrar fichero"); 25 } 26 }
- Cualquier System.out que hagamos después de redirigir la salida estándar será enviado al fichero "/tmp/salida.txt"
-- Ángel D. Fernández González -- (2017).
