Entrada/Salida
Transcription
Entrada/Salida
Entrada/Salida LSUB GSYC 22 de abril de 2015 (cc) 2015 Laboratorio de Sistemas, Algunos derechos reservados. Este trabajo se entrega bajo la licencia Creative Commons Reconocimiento NoComercial - SinObraDerivada (by-nc-nd). Para obtener la licencia completa, v´ ease http://creativecommons.org/licenses/. Tambi´ en puede solicitarse a Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA. Las im´ agenes de terceros conservan su licencia original. Entrada/salida • IO es la “vieja” biblioteca de entrada/salida de Java, orientado a streams. • NIO es la “nueva” biblioteca de entrada/salida de Java, orientado a buffers. File • Clase para representar el nombre abstracto de los ficheros. • No representa un fichero abierto (no es un descriptor de fichero). File • canExecute(), canRead(), canWrite(), setExecutable(), setReadable(), setWritable(), exists(), lenght(), isFile(), isHidden(), isDirectory(), ... • createNewFile() crea un fichero con un nombre dado de forma at´omica si el nombre no existe. • delete() borra el fichero. • mkdir() crea un directorio. • list()devuelve un array de Strings con los nombres del los ficheros (la lista no est´a ordenada). Stream • Representa una fuente o un sumidero de datos. • Oculta los detalles del dispositivo. • InputStream: todo lo que deriva de esta clase hereda un m´etodo read() para leer bytes. • OutputStream: todo lo que deriva de esta clase hereda un m´etodo write() para escribir bytes. Stream Imagen de The Java Tutorial: A Short Course on the Basics InputStream Distintos tipos, los b´asicos: • Filtros, FilterInputStream. Clase abstracta de la que heredan decorators que proporcionan funcionalidad extra para leer del stream (p.ej. lectura con buffer intermedio, bio). • Arrays de bytes, ByteArrayInputStream. Permite usar un buffer en memoria como un InputStream. • Strings, StringBufferInputStream. Convierte un String en un InputStream. • Ficheros, FileInputStream. Permite leer de un fichero. • Pipes, PipedInputStream. Implementa un pipe. • Una secuencia de otros streams (recopilados en un u ´nico stream), SequenceInputStream. Convierte dos o m´as InputStream en uno. InputStream p u b l i c i n t read ( byte [ ] b ) • Lee bytes y los deja en el buffer. • Si no hay datos disponibles se bloquea. • Devuelve el n´ umero de bytes le´ıdos, -1 cuando llega al final del fichero. • Levanta un IOException cuando el primer byte no se puede leer (excepto si es por un final de fichero), si se cierra el stream, o hay un IO error. • No confundir con readFully(byte[]), que lee datos hasta rellenar el buffer (bloqueante) o llegar a EOF (o IOException). InputStream p u b l i c i n t read ( byte [ ] b , i n t off , i n t l e n ) • Lee como mucho el tama˜ no indicado, pero puede leer menos. • Copia los datos al buffer a partir del offset indicado. • Si no hay datos disponibles se bloquea. • Devuelve el n´ umero de bytes le´ıdos, -1 cuando llega al final del fichero. • Levanta un IOException cuando el primer byte no se puede leer (excepto si es por un final de fichero), si se cierra el stream, o hay un IO error. InputStream public void close () • Cierra el stream y libera los recursos asociados. • Si se hace sobre un decorador, cierra el stream subyacente. FilterInputStream Decoran un input stream. Hay distintos tipos: • DataInputStream: permite leer tipos primitivos de forma portable (si en el otro lado hay un DataInputStream). • BufferedInputStream: entrada con buffer intermedio (buffered io). • ... DataInputStream Operaciones interesantes: • readByte(byte), readDouble(), readBoolean(), ...: leen un dato del tipo indicado. • Los tipos siempre se exportan con la misma longitud (p.ej. los int son 4 bytes, los long son 8 bytes, etc.) y en big-endian. OutputStream Distintos tipos, los b´asicos: • Filtros, FilterOutputStream. Clase abstracta de la que heredan decoradores que proporcionan funcionalidad extra para escribir en el stream (p.ej. escritura con buffer intermedio). • Arrays de bytes, ByteArrayOutputStream. Crea un buffer en memoria para guardar bytes. • Ficheros, FileOutputStream. Env´ıa datos a un fichero. • Pipes, PipedOutputStream. Env´ıa datos a un pipe. OutputStream p u b l i c void w r i t e ( byte [ ] b ) p u b l i c void w r i t e ( byte [ ] b , i n t off , i n t l e n ) • Escribe los bytes del buffer en el stream (el de tres par´ametros: copia len bytes desde desde el byte offset del buffer). • Levanta un IOException si hay un IO error. • Levanta un NullPointerException si el buffer es null. • El de tres par´ametros levanta un IndexOutOfBoundsException si el offset es negativo o se sale del array. OutputStream void f l u s h ( ) ; • Fuerza el vaciado del buffer del stream (si lo tiene). • Si se hace sobre un decorador, provoca el vaciado en el stream subyacente. Decoradores: ejemplo 1 F i l e O u t p u t S t r e a m s u m i d e r o = new F i l e O u t p u t S t r e a m ( ” /tmp/ a ” ) ; B u f f e r e d O u t p u t S t r e a m b i o = new B u f f e r e d O u t p u t S t r e a m ( s u m i d e r o ) ; DataOutputStream o d a t a = new DataOutputStream ( b i o ) ; odata . writeBoolean ( true ) ; odata . writeLong (1234L ) ; odata . writeDouble ( 3 . 1 4 1 6 ) ; odata . c l o s e ( ) ; // c i e r r a s u m i d e r o Decoradores: ejemplo 1 F i l e I n p u t S t r e a m f u e n t e = new F i l e I n p u t S t r e a m ( ” /tmp/ a ” ) ; B u f f e r e d I n p u t S t r e a m i b s = new B u f f e r e d I n p u t S t r e a m ( f u e n t e ) ; D a t a I n p u t S t r e a m i d a t a = new D a t a I n p u t S t r e a m ( i b s ) ; b = idata . readBoolean ( ) ; l = i d a t a . readLong ( ) ; d = i d a t a . readDouble ( ) ; idata . close (); System . o u t . p r i n t l n ( b + ” ” + l + ” ” + d ) ; // S a l i d a : t r u e 1234 3 . 1 4 1 6 Decoradores: ejemplo 2 B u f f e r e d O u t p u t S t r e a m o u t p u t= new B u f f e r e d O u t p u t S t r e a m ( new F i l e O u t p u t S t r e a m ( ” /tmp/ c ” ) ) ; DataOutputStream d a t a = new DataOutputStream ( o u t p u t ) ; b y t e b u f [ ] = ” e s t o e s u t f −8” . g e t B y t e s ( ”UTF−8” ) ; data . w r i t e I n t ( buf . l e n g t h ) ; d a t a . w r i t e ( buf , 0 , buf . length ) ; data . c l o s e ( ) ; Decoradores: ejemplo 2 B u f f e r e d I n p u t S t r e a m i n p u t = new B u f f e r e d I n p u t S t r e a m ( new F i l e I n p u t S t r e a m ( ” /tmp/ c ” ) ) ; D a t a I n p u t S t r e a m d a t a i n = new D a t a I n p u t S t r e a m ( i n p u t ) ; int len = datain . readInt ( ) ; b y t e b u f i n [ ] = new b y t e [ l e n ] ; datain . readFully ( bufin ); datain . close ( ) ; String i n s t r = new S t r i n g ( b u f i n , ”UTF−8” ) ; System . o u t . p r i n t ( i n s t r ) ; // s a l i d a : e s t o e s u t f −8 Readers y Writers • Similares a los streams, pero usados para texto. • Por ejemplo, u ´tiles para leer l´ınea a l´ınea con un BufferedReader. • Se pueden encadenar como los streams. • Se pueden combinar con streams. String line ; I n p u t S t r e a m s t r e a m = new F i l e I n p u t S t r e a m ( ” /tmp/b” ) ; R e a d e r l e c t o r = new I n p u t S t r e a m R e a d e r ( s t r e a m ) ; B u f f e r e d R e a d e r b i o = new B u f f e r e d R e a d e r ( l e c t o r ) ; w h i l e ( ( l i n e = b i o . r e a d L i n e ( ) ) != n u l l ) System . o u t . p r i n t l n ( l i n e ) ; bio . close ( ) ; // c i e r r a stream NIO NIO FileChannel • Clase de NIO para manipular un fichero. • Se obtiene a partir de un stream: getChannel(). • Tiene asociado un modo de apertura (lectura, escritura, ambos). • Tiene una posici´ on asociada (offset) . • Cuando se escribe m´ as all´a del final, el fichero crece. • El fichero puede truncarse. FileChannel Interfaz SeekableByteChannel: • position(): devuelve el offset. • position(long): establece el offset. • read(ByteBuffer): lee datos. • write(ByteBuffer): escribe datos. • truncate(long): trunca el fichero. Buffers • Hay buffers de distintos tipos. ByteBuffer, CharBuffer, DoubleBuffer FloatBuffer, IntBuffer, LongBuffer, ShortBuffer. • Nos centraremos en ByteBuffer. ByteBuffer • Es un buffer de bytes en crudo. • Creamos buffers reservando un tama˜ no dado o envolviendo otro tipo: ByteBuffer ByteBuffer byte [ ] b = ByteBuffer b1 = B y t e B u f f e r . a l l o c a t e ( 1 0 2 4 ) ; b2 = B y t e B u f f e r . wrap ( ” H o l a mundo” . g e t B y t e s ( ”UTF−8” ) ) ; new b y t e [ 2 5 6 ] ; b3 = B y t e B u f f e r . wrap ( b ) ; ByteBuffer Un buffer puede estar en uno de estos dos modos: • Escritura: Se van a escribir datos en el buffer. Se pasa a modo lectura llamando al m´etodo flip(). • Lectura: Se van a leer datos del buffer. clear() prepara el buffer para una nueva lectura. ByteBuffer Un buffer tiene asociado: • Capacidad: m´ aximo n´ umero de datos que caben en el buffer. capacity() devuelve la capacidad total del buffer. • Posici´ on: indica la posici´ on actual del buffer, y puede ir de 0 a capacidad − 1. Cuando se llama a flip() o a clear(), la posici´on pasa a ser 0. • L´ımite: En modo escritura es la capacidad del buffer. En modo lectura es el n´ umero de bytes se pueden leer del buffer. flip() hace que el l´ımite sea la posici´ on que hab´ıa en modo escritura. remaining() devuelve la cantidad de espacio que queda por rellenar/leer en el buffer. ByteBuffer Paso de modo escritura a modo lectura mediante un flip(): c J. Jenkov Imagen ByteBuffer: Slices • Una rodaja (slice) es un ByteBuffer que comparte los datos con el ByteBuffer del que se ha sacado. • Su capacidad, posici´ on y l´ımite son independientes. • Su posici´ on es 0 (a partir de la posici´ on del original en el momento de creaci´ on de la rodaja) • Su l´ımite y su capacidad son el n´ umero de bytes restantes en el original en el momento de crearlo. b y t e [ ] b = new b y t e [ 2 5 6 ] ; B y t e B u f f e r bb = B y t e B u f f e r . wrap ( b ) ; B y t e B u f f e r s l i = bb . s l i c e ( ) ; FileChannel public i n t read ( ByteBuffer dst ) • Hace un intento de leer r bytes y meterlos en el buffer, siendo r el n´ umero de bytes que quedan por rellenar en el buffer. • Un u ´nico read puede no rellenar el buffer, incluso puede que lea 0 bytes. • Devuelve el n´ umero le´ıdo, -1 al final del fichero. FileChannel public abstract int write ( ByteBuffer src ) • Escribe los bytes del buffer en el FileChannel, desde la posici´on actual. • Si se pasa del tama˜ no del fichero, el fichero crecer´a. • No retorna hasta que se hayan escrito los bytes solicitados. • Retorna el n´ umero de bytes escritos. FileChannel: ejemplo 1 B y t e B u f f e r b u f = B y t e B u f f e r . a l l o c a t e ( BSIZE ) ; w h i l e ( chan . r e a d ( b u f ) != −1){ buf . f l i p ( ) ; chanout . w r i t e ( buf ) ; buf . c l e a r ( ) ; } FileChannel: ejemplo 2 F i l e C h a n n e l chan = ( new F i l e O u t p u t S t r e a m ( ” /tmp/d” ) ) . g e t C h a n n e l ( ) ; B y t e B u f f e r b u f = B y t e B u f f e r . a l l o c a t e ( 1 0 ∗ I n t e g e r . SIZE / 8 ) ; I n t B u f f e r i b u f = buf . a s I n t B u f f e r ( ) ; f o r ( i n t i = 0 ; i < 1 0 ; i ++) i b u f . put ( i ) ; // no e s n e c e s a r i o h a c e r i b u f . f l i p ( ) // b u f t i e n e s u p o s i c i o n b i e n (0) chan . w r i t e ( b u f ) ; chan . c l o s e ( ) ; FileChannel: ejemplo 2 FileChannel inchan = ( new F i l e I n p u t S t r e a m ( ” /tmp/d” ) ) . g e t C h a n n e l ( ) ; B y t e B u f f e r i n b u f = B y t e B u f f e r . a l l o c a t e ( 1 0 ∗ I n t e g e r . SIZE / 8 ) ; int r ; do { r = inchan . read ( inbuf ) ; } w h i l e ( r != −1 && i n b u f . r e m a i n i n g ( ) > 0 ) ; chan . c l o s e ( ) ; inbuf . f l i p (); IntBuffer iinbuf = inbuf . asIntBuffer (); wh ile ( i i n b u f . remaining ( ) > 0) System . o u t . p r i n t ( i i n b u f . g e t ( ) + ” ” ) ; System . o u t . p r i n t l n ( ) ; // s a l i d a : 0 1 2 3 4 5 6 7 8 9 FileChannel p u b l i c abstract long transferFrom ( ReadableByteChannel src , long p o s i t i o n , long count ) publi c abstract long transferTo ( long p o s i t i o n , long count , WritableByteChannel target ) • Copia los bytes de un canal a otro. • Puede que no transfiera todos los bytes requeridos. • No modifica la posici´ on del canal de origen. • S´ı aumenta la posici´ on del canal de destino (se copian los n desde la posici´ on previa a la transferencia). • M´as eficiente que un bucle leyendo y escribiendo (se ahorra copias). FileChannel: ejemplo 3 FileChannel inchan = ( new F i l e I n p u t S t r e a m ( ” /tmp/ c ” ) ) . g e t C h a n n e l ( ) ; F i l e C h a n n e l outchan = ( new F i l e O u t p u t S t r e a m ( ” /tmp/ e ” ) ) . g e t C h a n n e l ( ) ; int o f f s e t = 0; long r ; while ( o f f s e t < inchan . s i z e ()){ r = inchan . transferTo ( offset , inchan . s i z e () − offset , outchan ) ; i f ( r == −1) break ; o f f s e t += r ; } inchan . c l o s e ( ) ; outchan . c l o s e ( ) ; FileChannel: gather-scatter publi c abstract long read ( ByteBuffer [ ] dsts , int offset , int length ) publi c abstract long w r i t e ( ByteBuffer [ ] srcs , int offset , int length ) • Usan una serie de buffers dispersos como un u ´nico buffer. FileChannel • Hay que cerrar el FileChannel cuando ya no se necesita. • Si el FileChannel se ha conseguido de un Stream, basta con cerrar el Stream. • Si se cierra el FileChannel, se cierra el Stream subyacente.