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.