Algoritmos y Estructura de Datos I Entrada/Salida. Streams. Melanie Sclar May 23, 2014 Melanie Sclar Algoritmos y Estructura de Datos I ¿Qué es un stream? Stream en inglés significa ”corriente” o ”torrente”. En nuestro caso, será una corriente de datos que según el caso puede representar una fuente de entrada o un destino de salida de datos del programa. Hay dos tipos principales de streams: Los input streams Los output streams Melanie Sclar Algoritmos y Estructura de Datos I Tipos de streams Un input stream es aquel que se utiliza para leer datos desde una fuente. Un output stream es aquel que se utiliza para escribir datos hacia un destino. Las clases básicas de input y output streams son InputStream y OutputStream respectivamente. Estas clases son muy básicas pues leen/escriben de a un byte. Por este motivo no serán muy prácticas, pero envolviéndolas en otras clases sı́ podrán serlo (ya lo veremos). Melanie Sclar Algoritmos y Estructura de Datos I Las versiones buffered de los streams Un buffer es un espacio de memoria donde se almacenan datos. Como los streams recién nombrados leen de a un byte, cada byte que se desee leer representará un nuevo llamado al sistema para pedirle que lea/imprima datos. Esto es muy costoso si vamos a leer/escribir numerosas veces. Melanie Sclar Algoritmos y Estructura de Datos I Para poder leer y escribir más ágilmente se crearon las clases BufferedInputStream y BufferedOutputStream. La ventaja de usar buffering es que si se va a leer/escribir varias veces, se guarda en memoria varios pedidos y se mandan todos de una sola vez. Esto permite que la lectura/escritura (que ya de por sı́ es lenta) se agilice pues se baja la cantidad de pedidos al sistema. Lo interesante del buffering es que nosotros no vemos ninguna diferencia: todo esto se manejará automáticamente. Melanie Sclar Algoritmos y Estructura de Datos I Los 3 streams estándar: System.in, System.out, System.err Los 3 streams estándar son el de entrada estándar (System.in), el de salida estándar (System.out) y el de error estándar (System.err). La entrada estándar es la que estuvieron usando hasta ahora: se leen los datos de entrada desde la consola. System.in es un InputStream para leer desde la entrada estándar. La salida estándar es la salida por pantalla. System.out es un OutputStream para escribir en la salida estándar. El error estándar es por donde se imprimen todas las excepciones del programa, junto con lo que nosotros queramos agregarle (errores que nosotros deseamos que se impriman por allı́). Se verá por la misma consola de la salida estándar (salvo que la redirijamos). Melanie Sclar Algoritmos y Estructura de Datos I Readers y Writers Ya vimos los streams más básicos, que dijimos que leen/escriben de a bytes. También observamos que esto es impráctico, y que nos gustarı́a tener alguna manera de leer de a chars/strings. Para lograr esto, utilizaremos los readers y los writers. A los readers se les pasará un InputStream (que lee de a bytes) y lo “envolverá”, de manera tal que ahora se pueda leer de a chars/strings. Análogamente, a un writer se le pasará un OutputStream y éste lo envolverá para que pueda escribir de a chars/strings. InputStreamReader inputStreamReader = new I n p u t S t r e a m R e a d e r ( System . i n ) ; Melanie Sclar Algoritmos y Estructura de Datos I Buffered Readers y Writers Al igual que con los streams antes vistos, también existe la versión buffered de los readers y writers. BufferedReader y BufferedWriter tomarán un reader/writer y lo envolverán para que tenga capacidad de buffering y ası́ ganar eficiencia. BufferedReader bufferedReader = new B u f f e r e d R e a d e r ( i n p u t S t r e a m R e a d e r ) ; Melanie Sclar Algoritmos y Estructura de Datos I Leer/Escribir de un archivo con Readers y Writers FileWriter y FileReader son clases que permitirán leer/escribir desde un archivo con la comodidad de hacerlo de a char/string. Para hacerlo, se tomará por parámetro el path del archivo, devolviéndose un reader o writer. F i l e R e a d e r f i l e R e a d e r = new F i l e R e a d e r ( ” a r c h i v o . i n ” ) ; Melanie Sclar Algoritmos y Estructura de Datos I Ejemplo de uso de reader y writer BufferedReader reader = new B u f f e r e d R e a d e r ( new I n p u t S t r e a m R e a d e r ( System . i n ) ) ; BufferedWriter writer = new B u f f e r e d W r i t e r ( new F i l e W r i t e r ( ” a r c h i v o . o u t ” ) ) ; r e a d e r . r e a d L i n e ( ) ; // Lee una l i n e a // l o puedo h a c e r p o r q u e ” r e a d e r ” e s B u f f e r e d R e a d e r w r i t e r . w r i t e ( ” s o y un s t r i n g ” ) ; // E s c r i b e un s t r i n g ¿Cómo escribo una lı́nea? Melanie Sclar Algoritmos y Estructura de Datos I Ejemplo de uso de reader y writer BufferedReader reader = new B u f f e r e d R e a d e r ( new I n p u t S t r e a m R e a d e r ( System . i n ) ) ; BufferedWriter writer = new B u f f e r e d W r i t e r ( new F i l e W r i t e r ( ” a r c h i v o . o u t ” ) ) ; r e a d e r . r e a d L i n e ( ) ; // Lee una l i n e a // l o puedo h a c e r p o r q u e ” r e a d e r ” e s B u f f e r e d R e a d e r w r i t e r . w r i t e ( ” s o y un s t r i n g ” ) ; // E s c r i b e un s t r i n g ¿Cómo escribo una lı́nea? Agrego \n al final del string, que es el caracter de fin de lı́nea. w r i t e r . w r i t e ( m i S t r i n g+” \n” ) ; Melanie Sclar Algoritmos y Estructura de Datos I Ejemplo de uso de reader y writer BufferedReader reader = new B u f f e r e d R e a d e r ( new I n p u t S t r e a m R e a d e r ( System . i n ) ) ; BufferedWriter writer = new B u f f e r e d W r i t e r ( new F i l e W r i t e r ( ” a r c h i v o . o u t ” ) ) ; r e a d e r . r e a d L i n e ( ) ; // Lee una l i n e a // l o puedo h a c e r p o r q u e ” r e a d e r ” e s B u f f e r e d R e a d e r w r i t e r . w r i t e ( ” s o y un s t r i n g ” ) ; // E s c r i b e un s t r i n g ¿Cómo escribo una lı́nea? Agrego \n al final del string, que es el caracter de fin de lı́nea. w r i t e r . w r i t e ( m i S t r i n g+” \n” ) ; ¿Cómo escribo un int? Melanie Sclar Algoritmos y Estructura de Datos I Ejemplo de uso de reader y writer BufferedReader reader = new B u f f e r e d R e a d e r ( new I n p u t S t r e a m R e a d e r ( System . i n ) ) ; BufferedWriter writer = new B u f f e r e d W r i t e r ( new F i l e W r i t e r ( ” a r c h i v o . o u t ” ) ) ; r e a d e r . r e a d L i n e ( ) ; // Lee una l i n e a // l o puedo h a c e r p o r q u e ” r e a d e r ” e s B u f f e r e d R e a d e r w r i t e r . w r i t e ( ” s o y un s t r i n g ” ) ; // E s c r i b e un s t r i n g ¿Cómo escribo una lı́nea? Agrego \n al final del string, que es el caracter de fin de lı́nea. w r i t e r . w r i t e ( m i S t r i n g+” \n” ) ; ¿Cómo escribo un int? Como estos writers sólo escriben de a strings, tengo que pasar el int a string (con el método valueOf) y luego imprimir. w r i t e r . write ( String . valueOf (3421343)) Melanie Sclar Algoritmos y Estructura de Datos I PrintWriter Como un writer sólo imprime de a strings o chars, si lo que deseamos imprimir es de otro tipo de dato deberemos pasarlo previamente a string (como hicimos con los enteros, llamando al método valueOf). Dado que esto es sumamente impráctico, podemos usar la clase PrintWriter que toma un writer y provee un método de impresión más cómodo (.print() para numerosos tipos de datos). PrintWriter printWriter printWriter printWriter p r i n t W r i t e r = new P r i n t W r i t e r ( w r i t e r ) ; . p r i n t l n ( ” E s t o i m p r i m e una l i n e a de t e x t o ” ) ; . print (2323); . p r i n t ( ”Ya no f a l t a n t a n t a s d i a p o s ! ” ) ; Melanie Sclar Algoritmos y Estructura de Datos I Scanner Scanner es una clase que facilita la lectura de datos. En cada lectura lee todos los caracteres que hay entre dos espacios en blanco, y según con qué método se lo haya llamado, los traduce automáticamente al tipo de dato especificado. S c a n n e r s c a n n e r = new S c a n n e r ( new B u f f e r e d R e a d e r ( new I n p u t S t r e a m R e a d e r ( System . i n ) ) ) ; S t r i n g s = s c a n n e r . n e x t ( ) ; // I n g r e s a e l s i g u i e n t e s t r i n g i n t j = s c a n n e r . n e x t I n t ( ) ; // I n g r e s a e l s i g u i e n t e i n t d o u b l e z z = s c a n n e r . n e x t D o u b l e ( ) ; // I n g r e s a un d o u b l e Melanie Sclar Algoritmos y Estructura de Datos I ¿Cómo cerramos un stream? Hasta ahora vimos cómo abrir un stream para poder leer/escribir de donde deseáramos. Es intuitivo suponer que si abrimos algo, cuando lo terminemos de usar lo tenemos que cerrar. Para eso existe el método ss.close(), si ss es el stream que deseamos cerrar. Es importantı́simo cerrar los streams luego de usarlos, y asegurarse de cerrarlos no importa qué pase en el programa. Veamos cómo. Melanie Sclar Algoritmos y Estructura de Datos I ¿Cómo cerramos un stream? (2) Supongamos que tenemos el siguiente código: p ub l ic s t a t i c void ejemplo () { F i l e W r i t e r e n t r a d a = new F i l e W r i t e r ( ” a r c h i v o . i n ” ) ; ... i n t x = 1000 / ( 1 0 % 2 ) ; ... entrada . close ( ) ; } ¿Este código termina bien? ¿Se cierra el stream? Melanie Sclar Algoritmos y Estructura de Datos I ¿Cómo cerramos un stream? (3) ¡No!, porque al intentar ejecutar la lı́nea donde definimos x se lanza una excepción de división por cero y termina el programa. En ese caso, no se llega a ejecutar la lı́nea del close, por lo que nunca cerramos el stream. Esto está mal, pues puede traer como consecuencia que no se termine de imprimir todo lo que se debı́a haber impreso. Melanie Sclar Algoritmos y Estructura de Datos I ¿Cómo cerramos un stream? (4) p u b l i c s t a t i c v o i d ejemploDeUsoDeUnStream ( ) { FileWriter entrada = n u l l ; try { e n t r a d a = new F i l e W r i t e r ( ” a r c h i v o . i n ” ) ; ... } finally { // E s t a s e c c i o n de c o d i g o s e e j e c u t a S I O S I i f ( e n t r a d a != n u l l ) { try { entrada . close ( ) ; } catch ( IOException e ) { e . printStackTrace ( ); } } } } Usando try/finally, nos aseguramos que la sección de código del finally se ejecute siempre, ya sea que haya terminado bien el código del try o no. Melanie Sclar Algoritmos y Estructura de Datos I Bibliografı́a http://docs.oracle.com/javase/tutorial/essential/io/streams.html Melanie Sclar Algoritmos y Estructura de Datos I