Sunteți pe pagina 1din 76

1 // Demostracin de los clics de ratn y cmo diferenciar entre los botones del ratn. 2 import java.awt.*; 3 import java.awt.event.

*; 4 import javax.swing.*; 5 public class DetallesRaton extends JFrame 6{ 7 private int xPos, yPos;

8 // establecer cadena barra ttulo; registrar escucha ratn; ajustar tamao y mostrar ventana 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 g.drawString( "Se hizo clic en: [" + xPos + ", " + yPos + "]", // dibujar objeto String en la ubicacin donde se hizo clic con el ratn public void paint( Graphics g ) { // llamar al mtodo paint de la superclase super.paint( g ); } setSize( 350, 150 ); setVisible( true ); addMouseListener( new ManejadorClicsRaton() ); public DetallesRaton() { super( "Clics y botones del ratn" );

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 } }

xPos, yPos );

public static void main( String args[] ) { DetallesRaton aplicacion = new DetallesRaton(); aplicacion.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

// clase interna para manejar eventos de ratn private class ManejadorClicsRaton extends MouseAdapter {

// manejar evento de clic del ratn y determinar cul botn se oprimi public void mouseClicked(MouseEvent evento) { xPos = evento.getX(); yPos = evento.getY();

String titulo = "Se hizo clic " + evento.getClickCount() + " Veces";

if ( evento.isMetaDown() ) // botn derecho del ratn titulo += " con el botn derecho del ratn";

else if ( evento.isAltDown() ) // botn de en medio del ratn titulo += " con el botn central del ratn";

52 53 54 55 56 57 58 59 60 61

else // botn izquierdo del ratn titulo += " con el botn izquierdo del ratn";

setTitle( titulo ); // establecer barra de ttulo de la ventana repaint();

} // fin del mtodo mouseClicked

} // fin de la clase interna privada ManejadorClicsRaton

62 } // fin de la clase DetallesRaton 1 // Demostracin de los eventos de pulsacin de tecla. 2 import java.awt.*; 3 import java.awt.event.*; 4 import javax.swing.*; 5 6 public class DemoTeclas extends JFrame implements KeyListener { 7 8 9 10 11 12 13 14 15 // establecer objeto JTextArea // configurar GUI public DemoTeclas() { super( "Demostracin de eventos de pulsacin de tecla" ); private String linea1 = "", linea2 = "", linea3 = ""; private JTextArea areaTexto;

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

areaTexto = new JTextArea( 10, 15 ); areaTexto.setText( "Oprima cualquier tecla en el teclado..." ); areaTexto.setEnabled( false ); areaTexto.setDisabledTextColor( Color.blue ); getContentPane().add( areaTexto );

addKeyListener( this ); // permitir al marco procesar eventos de teclas

setSize( 350, 100 ); setVisible( true );

} // fin del constructor de DemoTeclas

// manejar evento de pulsacin de cualquier tecla public void keyPressed( KeyEvent evento ) {

32 linea1 = "Se oprimi tecla: " + evento.getKeyText( evento.getKeyCode() ); 33 34 35 36 37 38 39 40 41 } // manejar evento de liberacin de cualquier tecla public void keyReleased( KeyEvent evento ) { linea1 = "Se solt tecla: " + evento.getKeyText( evento.getKeyCode() ); establecerLineas2y3( evento ); } establecerLineas2y3( evento );

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 public static void main( String args[] ) { DemoTeclas aplicacion = new DemoTeclas(); aplicacion.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); } areaTexto.setText( linea1 + "\n" + linea2 + "\n" + linea3 + "\n" ); linea3 = "Teclas modificadoras oprimidas: " + ( temp.equals( "" ) ? "ninguna" : temp ); String temp = evento.getKeyModifiersText( evento.getModifiers() ); // establecer segunda y tercera lneas de salida private void establecerLineas2y3( KeyEvent evento ) { linea2 = "Esta tecla " + ( evento.isActionKey() ? "" : "no " ) + "es una tecla de accin"; } // manejar evento de pulsacin de una tecla de accin public void keyTyped( KeyEvent evento ) { linea1 = "Se escribi tecla: " + evento.getKeyChar(); establecerLineas2y3( evento );

68 69

70 } // fin de la clase DemoTeclas Creacin archivos directos java


import java.lang.*; import java.io.*; class prog29 { public static void main(String[] args) { // creando e inicializando los campos del registro // observar que se debe usar clases numericas apropiadas int clave=0; String nombre=""; int edad=0; // abriendo archivo, capturando y grabando datos try { //* Creando y grabando a un archivo, esta larga la instruccin*/ File arch=new File("c:\\ajava\\archivo2.dat"); RandomAccessFile archivo=new RandomAccessFile(arch,"rw"); archivo.close(); } catch(FileNotFoundException fnfe) { /* Archivo no encontrado */ } catch (IOException ioe) { /* Error al escribir */ } // avisando System.out.println("ARCHIVO DIRECTO CREADO"); } // cierra main } // cierra clase

Ads by Google

Tutoriales I/O: Leer y Escibir Autor:Sun Traductor: Juan Antonio Palos (Ozito) I/O: Leer y Escribir o Introduccin a los Streams I/O o Serializacin de Objetos o Trabajar con Ficheros de Acceso Aleatorio o Y el Resto...

Introduccin a los Streams de I/O o Streams de Caracteres o Streams de Bytes o Entender las Superclases de I/O Usar Strings de Profundidad Como usar Streams de Ficheros Como usar Piped Streams o Usar Streams para Envolver otros Streams Usar Streams de Proceso Cmo Concatenar Ficheros Trabajar con Streams Filtrados o Usar Streams Filtrados o Cmo usar DataInputStream y DataOutputStream o

Escribir Nuestros Propios Streams Filtrados Cmo usar DataInputStream y DataOutputStream Escribir Streams Filtrados o La clase CheckedOutputStream o La Clase CheckedInputStream o El Interface Checksum y la clase Adler32 o Un Programa de Prueba o Filtrar Ficheros de Acceso Aleatorio Serializacin de Objetos Serializar Objetos o Cmo Escribir en un ObjectOutputStream? o Cmo Leer desde un ObjectInputStream? Proporcionar Serializacin de Objetos para Nuestras Clases o

Implementar el Interface Serializable o Personalizar la Serializacin o Implementar el Interface Externalizable o Proteger la Informacin Sensible Trabajar con Ficheros de Acceso Aleatorio o Usar Ficheros de Acceso Aleatorio o Escribir Filtros para Ficheros de Acceso Aleatorio Usar Ficheros de Acceso Aleatorio Escribir Filtros para Ficheros de Acceso Aleatorio o CheckedDataOutput contra CheckedOutputStream o CheckedDataInput contra CheckedInputStream o Los Programas Principales Y el Resto... 1

I/O: Leer y Escribir Frecuentemente los programas necesitan traer informacin desde una fuente externa o enviar informacin a una fuente externa. La informacin pueder estr en cualquier parte, en un fichero, en disco, en algn lugar de la red, en memoria o en otro programa. Tambin puede ser de cualquier tipo: objetos, caracteres, imgenes o sonidos. Para traer la informacin, un programa abre un stream sobre una fuente de informacin (un fichero, memoria, un socket) y lee la informacin serialmente, de esta forma: Similarmente, un programa puede enviar informacin a un destino externo abriendo un

stream sobre un destino y escribiendo la informacin serialmente, de esta forma: No importa de donde venga o donde vaya la informacin y tampoco importa el tipo de los datos que estn siendo ledos o escritos, los algoritmos para leer y escribir son casi siempre los mismos. Leer Escribir abrir un stream mientras haya informacin leer informacin cerrar el stream abrir un stream mientras haya informacin escribir informacin cerrar el stream El paquetejava. io contiene una coleccin de clases stream que soportan estos algoritmos para leer y escribir. Estas clases estn divididas en dos rboles basndose en los tipos de datos (caracteres o bytes) sobre los que opera. 2

Sin embargo, algunas veces es ms conveniente agrupar las clases basndose en su propsito en vez en los tipos de datos que lee o escribe. As, podemos agrupar los streams dependiendo de si leen u escriben lados en las "profundidades" o procesan la informacin que est siendo leda o escrita. Introduccin a los Streams I/O Esta seccin describe todos los tipos de streams y muestra las clases del paquetejava. io que los implementan de acuerdo a la divisin del rbol de clases. Luego, como mucha gente piensa en trminos de lo que quieren hacer en vez de lo que estn haciendo, proporcionamos dos secciones que nos muestran cmo usar los streams seleccionados basndonos en su propsito. Introducin a los Streams de I/O o

Streams de Caracteres o Streams de Bytes o Entender las Superclases de I/O Introducin a los Streams de I/O Streams de Caracteres Readery Writer son las superclases abstractas para streams de caracteres en java.io. 3

Reader proporciona el API y una implementacin parareaders-- streams que leen caracteres de 16-bits-- yWr it er proporciona el API y una implementacin paraw ri ters-streams que escriben caracteres de 16-bits. Las subclases deReader yWr it er que implementan streams especializados se dividen en dos categoras: aquellos que leen o escriben datos en profundidad (sinks) [mostrados en gris en la siguiente figura] y aquellos que realizan alguna suerte de proceso [mostrados en blanco]. La figura muestra el rbol de clases paraReader yWr it er. La mayora de los programas deberan usar este tipo de streams, ya que ambos pueden manejar caracteres en el conjunto de caracteres Unicode (mientras que los streams de bytes estn limitados a bytes ISO-Latin-1 de 8-bit). Streams de Bytes Los programas deberan usar los streams de bytes, descendientes deI nput St ream y OutputStream, para leer y escribir bytes de 8-bits. InputStreamy OutputStream

proporcionan el API y alguna implementacin streams de entrada y salida y leen y escriben bytes de 8-bits. Estos streams se usan normalmente para leer y escribir datos binarios como imgenes y sonidos. Al igual queReader yWr it er, las subclases deI nput St r eam yO ut put St r eam proporcionan I/O especializada que se divide en dos categorias: streams de profundidad y streams de procesamiento. La siguiente figura muestra el rbol de clases para los streams de bytes. 4

Como se ha mencionado, dos de las clases de streams de bytes,O bjectI nput St ream y ObjectOutputStream, se usan para la serializacin de objetos. Esta clases se cubren completamente en la pgina Serializacin de Objetos. Entender las Superclases de I/O Readery InputStream definen APIs similares pero para diferentes tipos de datos. Por ejemplo,Reader contiene estos mtodos para leer caracteres y arrays de caracteres: int read() int read(char cbuf[]) int read(char cbuf[], int offset, int length) InputStream defien los mismos mtodos pero para leer bytes o arrays de bytes: int read() int read(byte cbuf[]) int read(byte cbuf[], int offset, int length) Ambos tambin proporcionan mtodos para marcar localizaciones en el stream, saltar entradas y restablecer la posicin actual. Writery OutputStream son similarmente paralelas. Writer define tres mtodos para escribir caracteres y arrays de caracteres. int write(int c) int write(char cbuf[]) int write(char cbuf[], int offset, int length) YO ut put St r eam define los mismos mtodos pero para Bytes. 5

int write(int c) int write(byte cbuf[]) int write(byte cbuf[], int offset, int length) Todos estos streams --readers, writers, inputstreams, y outputstreams-- se abren automticamente cuando se crean. Podemos cerrar explcitamente cualquier stream llamando a su mtodoclose. O el recolector de basura puede cerrarlos implcitmamente, lo que ocurre cuando se deja de referenciar el objeto. Usar Strings de Profundidad Usar Strings de Profundidad Los streams de profundidad "sink" leen o escriben datos desde sitios especializados como strings, ficheros o tuberas (pipes). Tpicamente, cada reader o inputstream est pensado para un tipo especfico de fuente de entrada,java. io contiene un writer o un outputstream paralelo que pueden crearlo. La siguiente tabla nos muestra los streams de datos sink de java.io: Tipo de Sink Streams de Caracteres Streams de Bytes Memory CharArrayReader, CharArrayWriter, StringReader, StringWriter ByteArrayInputStream, ByteArrayOutputStream, StringBufferInputStream Pipe PipedReader, PipedWriter PipedInputStream, PipedOutputStream

File FileReader, FileWriter FileInputStream, FileOutputStream Observa que tanto el grupo de streams de caracteres como el bytes contienen parejas paralelas que operan con el tipo de sinks de datos. Estos se describen luego. CharArrayReader y CharArrayWriter ByteArrayInputStreamy ByteArrayOutputStream Estos streams se usan para leer y escribir desde memoria. Podemos crear estos streams sobre un array existente y luego usara los mtodos de lectura y escritura para leer y escribir desde el array. FileReader y FileWriter FileInputStreamy FileOutputStream Colectivamente llamados streams de ficheros, estos streams se usan para leer y escribir ficheros del sistema de ficheros nativo. Como usar Streams de Ficheros tiene un ejemplo que usaFileRead er yFileWr it er para copiar el contenido de un fichror a otro. PipedReader y PipedWriter

PipedInputStreamy PipedOutputStream Implementan los componentes de entrada y salida de una tubera. 6

Las tuberas (Pipes) se usan para canalizar la salida de un programa (o thread) hacia la entrada de otro programa (o thread). Puedes verPipedR eader yPipedWr it er en accin en la pgina Como usar Pipe Streams. StringReader y StringWriter StringBufferInputStream Se usaStr ingRea der para leer caracteres desde unSt r ing que reside en memoria. Se usaStr ingWr it er para escribir en unStr ing. StringWriter recoge los caracteres escritos en un StringBuffer, que puede ser convertido en unString.StringBufferInputStream es similar aStringReader, excepto en que lee bytes desde unStr ingBuf f er. Como usar Streams de Ficheros Como usar Streams de Ficheros Los streams de ficheros son quizs los ms fciles de entender. Simplemente ponemos, el stream de ficheros --FileReader,FileWr it er,FileI nput St r eam, yFileO ut put St r eam-- cada uno de lectura o escritura sobre un fichero del sistema de ficheros nativo. Podemos crear un stream de fichero desde un nombre de fichero en el formato de un string, desde un objetoFile, o desde un objetoFileDescr ipt or.

El siguiente programaCopy usaFileR eader yFileWr it er para copiar el contenido de un fichero llamadof arr ago. t xt en otro fichero llamadoout again. t xt. import java.io.*; public class Copy { public static void main(String[] args) throws IOException { File inputFile = new File("farrago.txt"); File outputFile = new File("outagain.txt"); FileReader in = new FileReader(inputFile); FileWriter out = new FileWriter(outputFile); int c; while ((c = in.read()) != -1) out.write(c); in.close(); out.close(); } }Este programa es muy sencillo. 7

AbreFileRead er sobref arr ago. t xt y abreFileWr it er sobreout again. t xt. El programa lee caracteres desde el reader mientras haya ms entradas en el fichero de entrada. Cuando la entrada se acada, el programa cierra tanto el reader como el writer. Observa el cdigo que usa el programaCopy para crear unFileR eader. File inputFile = new File("farrago.txt"); FileReader in = new FileReader(inputFile); Este cdigo crea un objetoFile que representa el fichero nombrado en el sistema de ficheros nativo.File es una clase de utilidad proporcionada porjava. io. Este programa usa este objeto slo para construir unFileRead er sobref arr ago. t xt.

Sin embargo, se podra usarinput File para obtener informacin sobref ar r ago. t xt, como su path completo. Despus de haber ejecutado el programa, deberamos encontrar una copia exacta de farrago.txt en un fichero llamado outagain.txt en el mismo directorio. Aqu est el contenido del fichero: So she went into the garden to cut a cabbage-leaf, to make an apple-pie; and at the same time a great she-bear, coming up the street, pops its head into the shop. 'What! no soap?' So he died, and she very imprudently married the barber; and there were present the Picninnies, and the Joblillies, and the Garyalies, and the grand Panjandrum himself, with the little round button at top, and they all fell to playing the game of catch as catch can, till the gun powder ran out at the heels of their boots. Samuel Foote 1720-1777 Recuerda queFileRead er yFileWr it er leen y escriben caracteres de 16 bits. Sin embargo, la mayora del sistemas de ficheros nativos estn basados en bytes de 8 bits. Estos streams codifican los caracteres segn operan de acuerdo al esquema de codificacin de caracteres por defecto. Podemos encontrar la codificacin de caracteres por defecto usandoSystem.getProperty("file.encoding"). Para especificar otra codificacin, deberamos construir unO ut put St reamWrit er sobre unFileO ut put St ream y especificarla. Para ms informacin sobre la codificacin de caracteres puedes ver la seccin Internationalization. Para curiosos, aqu tenemos otra versin de este programa,CopyBytes, que usa FileInputStreamy FileOutputStream en lugar de FileReadery FileWriter. Como usar Piped Streams o

Usar Streams para Envolver otros Streams Como usar Piped Streams 8

PipedReadery PipedWriter (y sus correspondientes streams de entrada y salida PipedInputStreamy PipedOutputStream) implementan los componentes de entrada y salida de una tubera. Las tuberas se utilizan para canalizar la salida de un programa (o thread) a la entrada de

otro programa (o thread) Por qu son tiles? Consideremos una clase que implementa varias utilidades de manipulacin de strings como ordenacin o inversin de texto. Sera bonito que la salida de uno de estos mtodos puediera ser usada como entrada del otro para que pudieramos encadenar una serie de llamadas a mtodos que realizan un funcin de gran importancia. Por ejemplo, podramos invertir todas las palabras de una lista, ordenarlas, y volver a invertirlas para crear una lista de palabrs rtmicas. Sin los streams de tuberas, el programa debera almacenar los resultados en algn lugar (como en un fichero o en la memoria) entre cada paso, como se ve aqu: Con los streams de tuberas, la salida de un mtodo puede ser dirigida hacia la entrada del siguiente, como se muestra en esta figura: Luego investigaremos un programa que implementa lo que representa el diagrama de la figura anterior. Este programa usaPipedRead er yPipedWr it er para conectar la entrada y la salida de sus mtodosreverse ysort para crear una lista de palabras rtmicas. Este programa se compone de varias clases. Esta seccin muestra y explica slo los elementos del programa que leen y escriben en las tuberas. Sigue los siguientes enlaces al cdigo para ver el programa completo. Primero, echemos un vistazo a la secuencia de llamada de los mtodosreverse ysort desde el mtodom ain en la claseRhym ingWor ds. FileReader words = new FileReader("words.txt"); Reader rhymingWords = reverse(sort(reverse(words))); 9

La llamada ms interna ar ever se toma unFileR eader abierto sobre el ficherowor ds. t xt que contiene una lista de palabras. El valor devuelto porreverse se pasa asort, cuyo valor de retorno es pasado a otra llamada ar ever se. Echemos un vistazo al mtodoreverse; el mtodosort es similiar y lo entenderemos una vez que comprendamosr ever se. public static Reader reverse(Reader source) { BufferedReader in = new BufferedReader(source); PipedWriter pipeOut = new PipedWriter(); PipedReader pipeIn = new PipedReader(pipeOut); PrintWriter out = new PrintWriter(pipeOut); new ReverseThread(out, in).start(); return pipeIn; }Las sentencias en negrita der ever se crean los dos puntos finales de una tubera --un PipedWriter y un PipedReader-- y los conecta construyendo el PipedReader "sobre" el PipedWriter. Cualquier cosa escrita en elPipedWr it er puede ser leda desde elPipedR eader. Las formas de conexin de tuberas se ilustran aqu:. reverse arranca unRever seThr ead que escribe su salida en el PipedWriter y devuelve el PipedReader al llamador.

Entonces el llamador preprara un thread de ordenacin para leerla. El mtodosort es exactamente lo mismo, excepto en que crea y arranca unSor t Thr ead. Usar Streams para Envolver otros Streams El mtodor ever se contiene algn cdigo interesante; en particular estas dos sentencias: BufferedReader in = new BufferedReader(source); ... PrintWriter out = new PrintWriter(pipeOut); La primera lnea abre unBufferedReader sobresource, el argumento a invertir (un Reader). Esto esencialmente "envuelve"sour ce en unBuff er edReader. 10

El programa lee desde elBuf f er edReader, que a su vez lee desdesour ce. El programa hace esto para poder usar el mtodo de convenienciareadLine de BufferedReader. De forma similar, elPipedWrit er es envuelto en unPrint Writ er para que el programa pueda usar el mtodo de convenienciapr int ln dePr int Wr it er. Frecuentemente veremos estreams envueltos de esta forma para as combinar las distintas caractersticas de varios streams. Intenta esto:

Escribe otra versin de este programa que use inputstreams y outputstreams en vez de readers y writers. Aqu puedes ver las soluciones: RhymingWords ReverseThread SortThread Usar Streams de Proceso Usar Streams de Proceso Los streams de proceso realizan alguna suerte de operacin, como almacenamiento o codificacin de caracteres, mientras leen o escriben. Al igual que de los stream de profundidad,java. io contiene parejas de streams. Uno que realiza una operacin particular durante la lectura y otro que realiza la misma operacin (o la inversa) durante la escritura. Esta tabla nos muestra los streams de proceso dejava. io: Proceso Stream de Caracteres Streams de Bytes Almacenamiento BufferedReader, BufferedWriter BufferedInputStream, BufferedOutputStream Filtrado FilterReader, FilterWriter

FilterInputStream, FilterOutputStream Conversin entre Bytes y Caracteres InputStreamReader, OutputStreamWriter Concatenacin SequenceInputStream Serializacin de Objetos ObjectInputStream, ObjectOutputStream Conversin de Datos DataInputStream, DataOutputStream Contaje LineNumberReader LineNumberInputStream Exploracin PushbackReader PushbackInputStream Impresin PrintWriter PrintStream Observa que muchas veces,java. io contiene streams de caracteres y de bytes que realizan el mismo proceso pero para diferentes tipos de datos.

11 BufferedReadery BufferedWriter BufferedInputStreamy BufferedOutputStream Almacenan los datos en buffers mientras leen o escriben, por lo tanto reduciendo as el nmero de accesos requeridos a la fuente de datos original. Los streams con buffer normalmente son ms eficientes que los que no lo utilizan. FilterReadery FilterWriter FilterInputStreamy FilterOutputStream Clases abstractas, como sus padres. Definen el interface para filtros de streams, que filtran los datos que estn siendo ledos o escritos. Trabajar con Streams Filtrados ms adelante en esta leccin, nos mostrar como usar filtros de streams y como implementar el nuestro propio. InputStreamReadery OutputStreamWriter Una pareja de reader y writer que realiza un puente entre streams de bytes y streams de caracteres. UnI nput St r eam Reader lee bytes desde unI nput St r eam y los convierte a caracteres usando la decodificacin de caracteres por defecto o una decodificacin de caracteres especificada por su nombre. De forma similar, unO ut put St r eam Wr it er convierte caracteres a bytes usando una decodificacin de caracteres por defecto o una decodificacin de caracteres especificada por su nombre y luego escribe estos bytes en unO ut put St r eam. Podemos aprender el nombre de la codificacin de caracteres por defecto llamando aSyst em . get Pr opert y( "f ile. encoding"). SequenceInputStream Concatena varios streams de entrada en un slo stream de entrada. Cmo Contanerar Ficheros tiene un pequeo ejemplo de esta clase. ObjectInputStreamy ObjectOutputStream Se usa para serializar objetos. Puedes ver Serializacin de Objetos. DataInputStreamy DataOutputStream Lee o escribir tipos de datos primitivos de Java de una forma independiente de la mquina.

Cmo usarDat aI nput Str eam yDat aO ut put St r eam nos ensea un ejemplo de uso de estos dos streams. LineNumberReadery LineNumberInputStream Sigue la pista del nmero de lnea mientras lee. PushbackReadery PushbackInputStream Dos streams cada uno con un caracter (o byte) de menos en el buffer. Algunas veces, cuando se leen datos desde un stream, encontraremos til explorar el siguiente tem del stream para decidir que hacer luego. Sin embargo, si lo exploramos, necesitaremos ponerlo de nuevo en su sitio para que pueda ser ledo y procesado normalmente. PrintWritery PrintStream Contienen mtodos de impresin de conveniencia. Estos son streams sencillos para escribir, por eso frecuentemente veremos otros streams envueltos en uno de estos. 12

Cmo Concatenar Ficheros Cmo Concatenar Ficheros SequenceInputStream crea un slo stream de entrada desde varias fuentes de entrada. Este programa de ejemploConcat enat e, usaSequenceI nput St ream para implementar la utilidad de concatenacin que secuencialmente concatena ficheros en el orden que son listados en la lnea de comandos: Esta es la clase controladora de la utilidadConcat enat e: import java.io.*; public class Concatenate { public static void main(String[] args) throws IOException { ListOfFiles mylist = new ListOfFiles(args);

SequenceInputStream s = new SequenceInputStream(mylist); int c; while ((c = s.read()) != -1) System.out.write(c); s.close(); } }Lo primero que hace esta clase es crear un objetoList O f Files llamadomylist que es inicializado con los argumentos de la lnea de comandos introducidos por el usuario. Los argumentos de la lnea de comandos listan los ficheros a concatenar. Se usamylist para inicializarSequenceI nput St r eam que usamylist para obtener un nuevoI nput St r eam para cada ficheros de lista: import java.util.*; import java.io.*; public class ListOfFiles implements Enumeration { private String[] listOfFiles; private int current = 0; public ListOfFiles(String[] listOfFiles) { this.listOfFiles = listOfFiles; }public boolean hasMoreElements() { if (current < listOfFiles.length) return true; else return false; } 13

public Object nextElement() { InputStream in = null; if (!hasMoreElements()) throw new NoSuchElementException("No more files."); else { String nextElement = listOfFiles[current]; current++; try { in = new FileInputStream(nextElement); } catch (FileNotFoundException e) { System.err.println("ListOfFiles: Can't open " + nextElement); } }return in; } }ListOfFiles implementa el interfaceEnumeration. Veremos como esto entra en juego cuando pasemos por el resto del programa. Despus el mtodom ain crea elSequenceI nput St r eam, lee un byte cada vez. Cuando el SequenceInputStream necesita un InputStream de una nueva fuente (como para el primer byte ledo o cuando alcanza el final del inputstream actual), llama anext Elem ent sobre el

objetoEnumeration para obetener el siguienteInputStream.ListOfFiles crea objetos FileInputStream enforma de lazo, lo que significa que siempre que SequenceInputStream llama anext Element,List Of Files abre unFileI nput St ream sobre el siguiente nombre de ficheros de la lista y devuelve el stream. Cuando elList Of Files llega al final de los ficheros a leer (no tiene ms elementos),next Elem ent devuelve null, y la llamada al mtodor ead deSequenceI nput St r eam devuelve -1 para indicar el final de la entrada. Concatenate simplemente hace eco de todos los datos leidos desde el SequenceInputStream a la salida estndar. Prueba Esto: Intenta ejecutarConcat enat e sobre los ficherosf ar r ago. t xt ywor ds.t xt que han sido usados como entradas para otros ejemplos de esta leccin. Trabajar con Streams Filtrados o Usar Streams Filtrados o Cmo usar DataInputStream y DataOutputStream o Escribir Nuestros Propios Streams Filtrados Trabajar con Streams Filtrados 14

Aadimos un stream filtrado a otro stream para filtrar los datos que estn siendo ledos o

escritos desde el stream original. El paquetejava.io contiene estos streams filtrados que son subclases de FilterInputStreamo FilterOutputStream. DataInputStreamy DataOutputStream BufferedInputStreamy BufferedOutputStream LineNumberInputStream PushbackInputStream PrintStream (este es un estream de salida) Esta seccin muestra cmo usar streams filtrados a travs de un ejemplo que usa un DataInputStream y un DataOutputStream. Adems, esta seccin muestra como escribir nuestros propios streams filtrados. Usar Streams Filtrados Para usar un stream de entrada o salida filtrado, adjuntamos el stream filtrado a otro stream de entrada o salida. Por ejemplo, podemos adjuntar unDat aI nput Str eam al stream de entrada estndar con el siguiente cdigo: DataInputStream dis = new DataInputStream(System.in); String input; while ((input = dis.readLine()) != null) {

. . . // do something interesting here }Podramos hacer esto para poder usar los mtodosr eadXXX ms convenientes, como un readLine, implementado por DataInputStream. Cmo usar DataInputStream y DataOutputStream Esta pgina cubre y explica un ejemplo de uso deDat aI nput Str eam yDat aO ut put Str eam, dos streams filtrados que pueden leer y escribir tipos de datos primitivos de Java. Escribir Nuestros Propios Streams Filtrados Muchos programadores podran encontrar que necesitan implementar sus propios streams que filtren o procesen datos que estn siendo ledos o escritos desde un stream. Algunas veces el proceso es independiente del formato de los datos, como el contaje de varios tems de un stream, y algunas veces el proceso est relacionado directamente con los propios datos o su formato, como la lectura y escritura de datos que estn contenidos en filas y columnas. Frecuentemente, estos programadores, subclasifican FilterOutputStreamy FilterInputStream para conseguir sus objetivos. Esta seccin describe un ejemplo de cmo subclasificarFileI nput St ream yFilt erO ut put St ream para crear nuestos propios filtros. Cmo usar DataInputStream y DataOutputStream 15 Cmo usar DataInputStream y DataOutputStream Este pgina muestra cmo usar las clasesDataInputStreamyDataOutputStream de java.io. Crea un ejemplo:Dat aI O Test, que lee y escribe datos tabulares (una factura de merchandising Java). Los datos tabulares estn formateados en columnas, donde cada columna est separada de la siguiente por un tab. Las columnas contienen los precios de

venta, el nmero de unidades pedidas, y una descripcin del tem, de esta forma: 19.99 12 Java T-shirt 9.99 8 Java Mug DataOutputStream, al igual que otros streams de salida filtrados, debe adjuntarse a algn otroO ut put St r eam. En este caso, se adjunta a unFileO ut put St r eam que est configurado para escribir en un fichero llamadoinvoice1. t xt. DataOutputStream dos = new DataOutputStream( new FileOutputStream("invoice1.txt")); Luego,DataIOTest usa mtodos especializadoswriteXXXdeDataOutputStream para escribir los datos de la factura (contenida dentro de arrays en el programa) de acuerdo a los tipos de datos que se estn escribiendo. for (int i = 0; i < prices.length; i ++) { dos.writeDouble(prices[i]); dos.writeChar('\t'); dos.writeInt(units[i]); dos.writeChar('\t'); dos.writeChars(descs[i]); dos.writeChar('\n'); }dos.close(); Observa que este cdigo cierra el stream de salida cuando ha finalizado. Luego,Dat aIO Test abre unDat aI nput Str eam sobre el fichero que acaba de escribir. DataInputStream dis = new DataInputStream( new FileInputStream("invoice1.txt")); DataInputStream tambin debe adjuntar algn otro InputStream; en este caso, un

FileInputStream configurado para leer el fichero que acaba de escribir --invoice1.txt. DataIOTest luego slo lee los datos usando los mtodos especializados readXXXde DataInputStream: try { while (true) { price = dis.readDouble(); dis.readChar(); // throws out the tab unit = dis.readInt(); 16

dis.readChar(); // throws out the tab desc = dis.readLine(); System.out.println("You've ordered " + unit + " units of " + desc + " at $" + price); total = total + unit * price; } } catch (EOFException e) { }System.out.println("For a TOTAL of: $" + total); dis.close(); Cuando se han ledo todos los datos,Dat aI O Test muestra una sentencia sumarizando el pedido y la cantidad debida, y cierra el stream. Observa el bucle que usaDat aIO Test para leer los datos desde elDat aI nput Str eam. Normalmente, cuando se lee usaremos un bucle como este:

while ((input = dis.readLine()) != null) { .. . }El mtodor eadLine devuelve un valor, null, que indica que se ha alcanzado el fin del fichero. Muchos de los mtodosreadXXX deDat aI nput Stream no pueden hacer esto porque cualquier valor devuelto para indicar fin-de-fichero podra ser un valor ledo legtimamente desde el stream. Por ejemplo, supongamos que queremos usar -1 para indicar el fin-de-fichero. Bien, no podemos usarlo porque -1 es un valor legtimo que puede ser ledo desde el stream de entrada usandor eadDouble,r eadI nt, o uno de los otros mtodos de lectura que leen nmeros. Por eso el mtodor eadXXXdeDat aI nput St r eam lanza unaEO FExcept ion en su lugar. Cuando ocurreEO FExcept ion termina el while (true). Cuando ejecutemos el programaDat aI O Test deberamos ver la siguiente salida: You've ordered 12 units of Java T-shirt at $19.99 You've ordered 8 units of Java Mug at $9.99 You've ordered 13 units of Duke Juggling Dolls at $15.99 You've ordered 29 units of Java Pin at $3.99 You've ordered 50 units of Java Key Chain at $4.99 For a TOTAL of: $892.88 Escribir Streams Filtrados o La clase CheckedOutputStream o La Clase CheckedInputStream o El Interface Checksum y la clase Adler32 o Un Programa de Prueba o Filtrar Ficheros de Acceso Aleatorio

17

Escribir Streams Filtrados Lo siguiente es una lista de pasos a realizar cuando escribamos nuestro propios streams filtrados tanto de entrada como de salida. Crear una subclase deFilt erI nput St ream yFilt erO ut put St ream. Normalmente los streams de entrada y salida vienen en parejas, por eso necesitamos crear las dos versin del stream filtrado. Sobreescribir los mtodosr ead ywr it e. Sobreescribir cualquier otro mtodo que pudieramos necesitar. Aseguranos de que los streams de entrada y salida funcionan juntos. Esta seccin nos muestra cmo implementar nuestros propios streams filtrados a travs de un ejemplo que implementa una pareja de streams filtrados de entrada y salida. Tanto el stream de entrada como el de salida usan una clase checksum para calcular el checksum de los datos escritos o ledos desde el stream. El checksum se usa para determinar si los datos ledos por el stream de entrada corresponden con los datos escritos por el stream de salida. Cuatro clases y un interface componen este programa de ejemplo: Las subclases de los streams de entrada y salida filtrados-CheckedOutputStream

yCheckedI nput St r eam. El interfaceChecksum y la claseAdler 32 calculan un checksum para los streams. La claseCheckedI O Test define el mtodom ain para el programa. La claseCheckedO ut put St ream La claseCheckedO ut put St ream es una subclase deFilt erO ut put St ream que calcula un checksum sobre los datos que estn siendo escritos en el stream. Cuando se crea un CheckedOutputStream, debemos usar su nico constructor. public CheckedOutputStream(OutputStream out, Checksum cksum) { super(out); this.cksum = cksum; }Este constructor toma un argumentoO ut put St r eam y otroChecksum. El argumentoO ut put St r eam es el stream de salida que esteCheckedO ut put St r eam debe filtrar. El argumentoChecksum es un objeto que calcula un checksum. CheckedOutputStream se autoinicializa llamando al constructor de su superclase e inicializando una variable privada ,cksum, con el objetoChecksum. El CheckedOutputStreamusa cksum para actualizar el checksum cada vez que se escribe un dato en el stream. 18

CheckedOutputStream necesita sobreescribir los mtodos writede FilterOutputStream para que cada vez que se llame al mtodowrite, se actualice el checksum. FilterOutputStream define tres versiones del mtodo write.

1.write(int i) 2.write(byte[] b) 3.write(byte[] b, int offset, int length) CheckedOutputStream sobreescribe estos tres mtodos. public void write(int b) throws IOException { out.write(b); cksum.update(b); }public void write(byte[] b) throws IOException { out.write(b, 0, b.length); cksum.update(b, 0, b.length); }public void write(byte[] b, int off, int len) throws IOException { out.write(b, off, len); cksum.update(b, off, len); }Las implementaciones de estos tres mtodoswr it e son correctas: escriben los datos en el stream de salida al que este stream est adjuntado, luego actualiza el checksum. La ClaseCheckedI nput St r eam La claseCheckedI nput St r eam. CheckedInputStream es una subclase de FilterInputStream que calcula un checksum de los datos que estn siendo ledos desde el stream. Cuando se crea un CheckedInputStream, debemos usar su nico constructor: public CheckedInputStream(InputStream in, Checksum cksum) { super(in); this.cksum = cksum; }Este constructor es similar al de la claseCheckedO ut put St r eam. Slo queCheckedOutputStream necesita sobreescribir los mtodoswrite de FilterOutputStream, CheckedInputStream debe sobreescribir los mtodos readde

FilterInputStream para que cada que vez que se llame al mtodo read, se actualice el checksum. Como conFilterOutputStream,FilterInputStream define tres versiones del mtodor ead yCheckedI nput St r eam las sobreescribe todas. public int read() throws IOException { int b = in.read(); if (b != -1) { 19

cksum.update(b); }return b; }public int read(byte[] b) throws IOException { int len; len = in.read(b, 0, b.length); if (len != -1) { cksum.update(b, 0, len); }return len; }public int read(byte[] b, int off, int len) throws IOException { len = in.read(b, off, len); if (len != -1) { cksum.update(b, off, len); }return len; }Las implementaciones de estos tres mtodosr ead son correctas: leen los datos desde el stream de entrada al que est adjunto este stream filtrado; entonces si se ley realmente algn dato, se actualiza el checksum. El InterfaceChecksum y la claseAdl er 32

El interfaceChecksum define cuatro mtodos para que lo implementen los objetos checksum; estos mtodos resetean, actualizan y devuelven el valor del checksum. Podramos escribir una claseChecksum que calcule un tipo especfico de checksum como el CRC-32. Observa que la herencia en el checksum es la nocin de estado. El objeto checksum no slo calcula un checksum y ya est. En vez de eso, el checksum es actualizado cada vez que se lee o se escribe informacin en el stream para el que este objeto calcula el checksum. Si queremos reutilizar un objeto checksum, debemos resetearlo. Para este ejemplo, hemos implementado el checksumAdler 32, que es casi una versin del checksum CRC-32 pero puede ser calculado ms rpidamente. Un Programa de Prueba La ltima clase del ejemplo,CheckedI O Test, contiene el mtodom ain para el programa. import java.io.*; public class CheckedIOTest { public static void main(String[] args) throws IOException { Adler32 inChecker = new Adler32(); Adler32 outChecker = new Adler32(); CheckedInputStream in = null; 20 CheckedOutputStream out = null; try { in = new CheckedInputStream( new FileInputStream("farrago.txt"), inChecker); out = new CheckedOutputStream( new FileOutputStream("outagain.txt"), outChecker); } catch (FileNotFoundException e) { System.err.println("CheckedIOTest: " + e); System.exit(-1);

} catch (IOException e) { System.err.println("CheckedIOTest: " + e); System.exit(-1); }int c; while ((c = in.read()) != -1) out.write(c); System.out.println("Input stream check sum: " + inChecker.getValue()); System.out.println("Output stream check sum: " + outChecker.getValue()); in.close(); out.close(); } }El mtodom ain crea dos objetosAdler 32, uno para unCheckedO ut put St r eam y otro para unCheckedI nput St ream. El ejemplo requiere dos objetos checksum porque los objetos checksum se actualizan durante las llamadas a lo mtodosread ywrit e que ocurren concurrentemente. Luego,m ain abre unCheckedI nput St r eam sobre un pequeo fichero de texto,f arrago. t xt, y unCheckedO ut put St r eam sobre un fichero de salida llamadoout again. t xt, que no existe hasta que ejecutemos el programa por primera vez. El mtodom ain lee el texto desde elCheckedI nput St ream y simplemente lo copia en el CheckedOutputStream. Los mtodos ready write usan los objetos Adler32 para calcular un checksum durante la lectura y escritura. Despus de haber ledo completamente el fichero de entrada (y consecuentemente se haya completado de escribir el fichero de salida), el programa imprime los checksums de los dos streams (que deben ser iguales) y cierra los dos streams. Cuando ejecutemosCheckedI O Test, deberamos ver esta salida: Input stream check sum: 736868089

Output stream check sum: 736868089 21

Filtrar Ficheros de Acceso Aleatorio Todos los streams filtrados dejava. io descienden deI nput St ream oO ut put St ream, que implementan ficheros de acceso secuencial. Por eso si subclasificamosFilt er I nput St r eam oFilterOutputStream nuestros streams filtrados tambin sern ficheros de acceso secuencial. Escribir Filtros para Ficheros de Acceso Aleatorio, ms adelante en esta leccin nos muestra cmo re-escribir este ejemplo para que funcione sobre unRandomAccessFi le tambin como sobre unDat aI nput Str eam o unDat aO ut put St r eam. Serializacin de Objetos Serializacin de Objetos El paquetejava.io tiene otros dos streams de bytes--ObjectInputStream y ObjectOutputStream-- que funcionan como los otros streams de entrada y salida. Sin embargo, son especiales porque pueden leer y escribir objetos. La clave para escribir objetos es representar su estado de una forma serializada suficiente para reconstruir el objeto cuando es ledo. Por eso, leer y escribir objetos es un proceso llamado serializacin de objetos. La serializacin de objetos es esencial para construir todo excepto las aplicaciones ms temporales. Podemos usar la serializacin de objetos de las siguientes formas:

Invocacin Remota de Mtodos (RMI)--comunicacin de objetos mediante sockets Persistencia de Peso Ligero-- el archivo de un objeto para una invocacin posterior en el mismo programa. Como programador Java, necesitamos conocer la serializacin de objetos desde dos puntos de vista. Primero, necesitamos saber cmo serializar objetos escribiendolos a un ObjectOutputStream y luego leerlos de nuevo usando un ObjectInputStream. La siguiente pgina, Serializar Objetos, nos muestra cmo hacerlo. Segundo, querremos conocer como escribir una clase para que sus ejemplares puedan ser serializados. Podemos ver como se hace esto en la pgina: Proporcionar Serializacin de Objetos para Nuestras Clases. Serializar Objetos o Cmo Escribir en un ObjectOutputStream? o Cmo Leer desde un ObjectInputStream? Serializar Objetos Reconstruir un objeto desde un stream requier primero que el objeto se haya escrito en un stream. Por eso empezaremos por aqu: 22

Cmo Escribir en un ObjectOutputStream? Escribir objetos a un stream es un proceso sencillo. Por ejemplo, aqu obtenemos la hora actual en milisegundos construyendo un objetoDat e y luego serializamos ese objeto. FileOutputStream out = new FileOutputStream("theTime"); ObjectOutputStream s = new ObjectOutputStream(out); s.writeObject("Today"); s.writeObject(new Date()); s.flush(); ObjectOutputStream es un stream de proceso, por eso debe construirse sobre otro stream. Este cdigo construye unO bject O ut put St ream sobre unFileO ut put St ream, para serializar el objeto a un fichero llamadot heTim e. Luego, el stringToday y un objetoDate se escriben en el stream con el mtodo writeObjectde ObjectOutputStream. Si un objeto se refiere a otro objeto, entonces todos los objetos que son alcanzables desde el primero deben ser escritos al mismo tiempo para poder mantener la relacin entre ellos. As, el mtodowriteObject serializa el objeto especificado, sigue sus referencias a otros objetos recursivamente, y tambin los escribe todos. El streamO bject O ut put St ream implementa el interfaceDat aO ut put que define muchos mtodos para escribir tipos de datos primitivos, comowrit eI nt,writ eFloat, owrit eUTF. Podemos usar estos mtodos para escribir tipos de datos primitivos a un ObjectOutputStream. El mtodowriteObject lanza unaNotSerializab leExce ption si el objeto dado no es serializable. Un objeto es serializable slo si clase implementa el interfaceSer ializab le. Cmo Leer desde un ObjectInputStream? Una vez que hemos escrito objetos y tipos de datos primitivos en un stream, querremos leerlos de nuevo y reconstruir los objetos. Esto tambin es sencillo.

Aqu est el cdigo que lee elStr ing y el objetoDat e que se escribieron en el fichero llamadot heTime del ltimo ejemplo. FileInputStream in = new FileInputStream("theTime"); ObjectInputStream s = new ObjectInputStream(in); String today = (String)s.readObject(); Date date = (Date)s.readObject(); CmoO bject O ut put St ream,O bjectI nput St ream debe construirse sobre otro stream. En este ejemplo, los objetos fueros archivados en un fichero, por eso el cdigo construye un ObjectInputStream sobre un FileInputStream. Luego, el cdigo usa el mtodo readObject deO bjectI nput St ream para leer elSt ring y el objetoDat e desde el fichero. Los objetos deben ser ledos desde el stream en el mismo orden en que se esribieron. Observa que el valor de retorno dereadObject es un objeto que es forzado y asignado a un tipo especfico. 23

El mtodoreadObject des-serializa el siguiente objeto en el stream y revisa sus referencias a otros objetos recursivamente para des-serializar todos los objetos que son alcanzables desde l. De esta forma, mantiene la relacin entre los objetos. El streamO bject I nput Str eam implementa el interfaceDat aI nput que define mtodos para leer tipos de datos primitivos. Los mtodos deDat aI nput son paralelos a los definidos en DataOutput para escribir tipos de datos primitivos. Entre ellos se incluyen readInt, readFloat,y readUTF. Se usan estos mtodos para leer tipos de datos primitivos desde un ObjectInputStream. Proporcionar Serializacin de Objetos para Nuestras Clases o

Implementar el Interface Serializable o Personalizar la Serializacin o Implementar el Interface Externalizable o Proteger la Informacin Sensible Proporcionar Serializacin de Objetos para Nuestras Clases Un objeto es serializable slo si su clase implementa el interfaceSerializ able. As, si queremos serializar un ejemplar de una de nuestras clases, la clase debe implementar este interface. Las buenas noticias es queSerializab le es un interface vaco. Es decir, no contiene ninguna declaracin de mtodo; su propsito es simplemente identificar las clases cuyos objetos son serializables. Implementar el Interface Serializable Aqu tenemos la definicin completa del interfaceSer ializ able: package java.io; public interface Serializable { // there's nothing in here! }; Crear ejemplares de una clase serializable es fcil. Slo hay que aadir la clasula implements Serializable a la declaracin de nuestra clase: public class MySerializableClass implements Serializable { ... }No tenemos que escribir ningn mtodo. La serializacin de un ejemplar de esta clase la maneja el mtododef ault Wr it eO bject deO bject O ut put St r eam.

Este mtodo escribe cualquier cosa necesaria para reconstruir un ejemplar de la clase, incluyendo lo siguiente: La clase del Objeto La firma de la clase Los valores para todos los miembros no-transient y no-static, incluyendo los miembros que se refieren a otros objetos. 24

Para muchas clases, este comportamiento por defecto es suficiente. Sin embargo, la serializacin por defecto puede ser lenta, y las clases podran querer un control ms explicito sobre la serializacin. Personalizar la Serializacin Podemos personalizar la serializacin de nuestras clases proporcionando dos mtodos para ella:wr it eO bject yr eadO bject. El mtodowrit eO bject controla la informacin que se graba. Normalmente se usa para aadir informacin adicional al stream. El mtodor eadO bject lee la informacin escrita por el correspondiente mtodowr it eO bject o puede usarse para actualizar el estado del objeto despus de haber sido restaurado. El mtodowriteObject debe declarse exactamente como se muestra en el siguiente ejemplo. Lo primero que debe hacer es llamar al mtododef ault Wr it eO bject para realizar la serializacin por defecto. Cualquier ajuste puede realizarse despus. private void writeObject(ObjectOutputStream s) throws IOException { s.defaultWriteObject(); // customized serialization code

}El mtodor eadO bject debe leer todo lo escrito porwr it eO bject en el mismo orden en que se escribi. El mtodor eadO bject tambin puede realizar clculos o actualizar el estado del objeto de alguna forma. Aqu est el mtodor eadO bject que corresponde al mtodo writeObjectant er ior : private void readObject(ObjectInputStream s) throws IOException { s.defaultReadObject(); // customized deserialization code ... // followed by code to update the object, if necessary }El mtodor eadO bject debe declarse exactamente como se ha mostrado. Los mtodoswrit eO bject yreadO bject son responsalbes de serializar slo las clases inmediatas. Cualquier serializacin requerida por la superclase se maneja automticamente. Sin embargo, una clase que necesita coordinarse explcitamente con su superclase para serializarse puede hacerlo implementando el interfaceExt er nalizable. Implementar el Interface Externalizable Para un completo control explcito del proceso de serializacin, una clase debe implementar el interfaceExt er nalizabl e. Para los objetosExt ernalizabl e slo la identidad de la clase del objeto es grabada automticamente en el stream. La clase es responsable de escribir y leer sus contenidos, y debe estar coordinada con su superclase para hacerlo. 25

Aqu tenemos una definicin completa del interfaceExt ernalizable que desciende del interfaceSer ializ able: package java.io; public interface Externalizable extends Serializable {

public void writeExternal(ObjectOutput out) throws IOException; public void readExternal(ObjectInput in) throws IOException, java.lang.ClassNotFoundException; }Lo siguiente sirve para una claseExt er nalizable: Debe implementar el interfacejava. io. Ext er nalizabl e. Debe implementar un mtodowriteExternal para salvar el estado del objeto. Tambin, debe coordinarse explcitamente con sus superclase para salvar su estado. Debe implementar el mtodoreadExternal para leer los datos escritos por el mtodowriteExternal desde el stream y restaurar el estado del objeto. Debe coordinarse explctamente con su superclase para restaurar sus estado. Si se estn escribiendo formatos definidos externamente, los mtodos writeExternaly readExternal son los nicos responsables de esos formatos. Los mtodoswrit eExt ernal yreadExt ernal son pblicos y corren el riesgo de que un cliente pueda escribir o leer informacin en el objeto distinto usando sus mtodos y campos. Estos mtodos deben se usarse solamente cuando la informacin contenida en el objeto no sea importante o cuando exponer dicha informacin no represente un riesgo de seguridad. Proteger la Informacin Sensible Cuando desarrollamos una clase que proporcione acceso controlado a recursos, debemos tener cidado de proteger la informacin y las funciones sensibles. Durante la des- serializacin, se restaura el estado privado del objeto. Por ejemplo, un descriptor de fichero contiene un manejador que propociona acceso a un recurso del sistema operativo. Siendo posible olvidar que un descriptor de fichero puede permitir ciertas formas de accesos ilegales, ya que la restauracin del estado se hace desde un stream. Por lo tanto en el momento de la serializacin se debe tener cuidado y no creer que el stream contiene slo representaciones vlidas de objetos. Para evitar comprometer una clase,

debemos evitar que el estado sensible de un objeto sea restaurado desde un stream o que sea reverificado por la clase. Hay disponibles varias tcnicas para proteger los datos sensibles. La ms sencilla es marcar los campos que contienen los datos sensibles como privatetr ansient. Los campostr ansient yst at ic no son serializados. Marcando el campo evitaremos que el estado aparezca en el stream y sea restaurado durante la desserializacin. Como la lectura y escritura (de campos privados) no puede hacerde desde fuera de la clase, los campostr ansient de la clase son seguros. 26

Las clases particularmente sensibles no debe ser serializadas. Para conseguir esto, el objeto no debe implementar ninguno de los interfacesSer ializab le niExt er nalizabl e. Algunas clases podran encontrar beneficioso permitir la escritura y lectura pero especficamente manejadas y revalidar el estado cuando es des-serializado. La clase debera implementar los mtodoswr it eO bject yr eadO bject para salvar y recuperar slo el estado apropiado. Si el acceso debe ser denegado, lanzar unaNot Serializab leExce pt ion evitar accesos posteriores. Trabajar con Ficheros de Acceso Aleatorio

o Usar Ficheros de Acceso Aleatorio o Escribir Filtros para Ficheros de Acceso Aleatorio Trabajar con Ficheros de Acceso Aleatorio Hasta ahora los streams de entrada y salida de esta leccin han sido streams de acceso secuencial, streams cuyo contenido debe ser ledo o escrito secuencialmente. A pesar de su increible utilidad, los ficheros de acceso secuencial son una consecuencia de un medio secuencial como una cinta magntica. Los ficheros de acceso aleatorio, por otro lado, permiten acceso no secuencial, o aleatorio, a los contenidos de un fichero. Pero por qu necesitamos ficheros de acceso aleatorio. Consideremos el formato de archivo conocido como "zip". Los archivos Zip contienen ficheros que normalmente estn comprimidos para ahorrar espacio. Los archivos Zip tambin contienen al final un directorio de entradas que indica donde empiezan los distintos ficheros contenidos enel archivo Zip. Supongamos que queremos extraer un fichero especfico de un archivo Zip. Si usamos un stream de acceso secuencial, tenemos que hacer lo siguiente: Abrir el fichero Zip. Buscar a travs del fichero Zip hasta localizar el fichero que queremos extraer. Extraer el fichero. Cerrar el archivo Zip. Como media, usando este algoritmo, tendramos que leer la mitad del archivo Zip antes de encontrar el fichero que queremos extraer. Podemos extraer el mismo fichero del archivo Zip de forma ms eficiente usando la caracterstica "seek" de un fichero de acceso aleatorio:

Abrimos el fichero Zip. Saltamos al directorio de entradas y localizamos la entrada del fichero que queremos extraer del archivo Zip. Saltamos (hacia atrs) dentro del archivo Zip a la posicin del fichero a extraer. Extraemos el fichero. 27

Cerramos el archivo Zip. Este algoritmo es ms eficiente porque slo tenemos que leer el directorio de entradas y

el fichero que queremos extraer. La claseRandom AccessF ile del paquetejava. io implementa ficheros de acceso aleatorio. Usar Ficheros de Acceso Aleatorio Usar Ficheros de Acceso Aleatorio La claseRandom AccessF ile implementa los interfacesDat aI nput yDat aO ut put y por lo tanto puede usarse para leer y escribir.Random AccessFi le es similar aFileI nput St r eam y FileOutputStream en que especificamos un fichero del sistema de ficheros nativo para abrirlo cuando lo creamos. Podemos hacer esto con un nombre de fichero o un objeto File. Cuando creamos unRandom AccessF ile, debemos indicar si slo queremos leer o tambin queremos escribir en el fichero. (tenemos que poder leer un fichero para poder escribirlo). La siguiente lnea de cdigo cea unRandomAccessFi le que lee el fichero llamadof ar r ago. t xt: new RandomAccessFile("farrago.txt", "r"); Y esta abre el mismo fichero tanto para lectura como para escritura: new RandomAccessFile("farrago.txt", "rw"); Despus de haber abierto el fichero, podemos usar los mtodos comunesreadXXX o writeXXX para realizar I/O en el fichero. RandomAccessFile soporta la nocin de puntero de fichero. Este puntero indica la posicin actual en el fichero, cuando el fichero se crea por primera ver, el puntero de fichero es 0, indicando el principio del fichero. Las llamadas a los mtodosreadXXX y

writeXXX ajustan la posicin del puntero de fichero segn el nmero de bytes ledos o escritos. Adems de los mtodos de I/O normales que implcitamente mueven el puntero de fichero cuando ocurre la operacin,RandomAccessF ile contiene tres mtodos que manipulan explcitamente el puntero de fichero: skipBytes Mueve el puntero hacia adelante el nmero de bytes especificado. seek Posiciona el puntero de fichero en la posicin anterior al byte especificado. getFilePointer Devuelve la posicin actual (byte) del puntero de fichero. 28

Escribir Filtros para Ficheros de Acceso Aleatorio o CheckedDataOutput contra CheckedOutputStream

o CheckedDataInput contra CheckedInputStream o Los Programas Principales Escribir Filtros para Ficheros de Acceso Aleatorio Reescribamos el ejemplo de Escribir Nuestros Propios Streams Filtrados para que funcione sobreRandom AccessF iles. ComoRandom AccessF ile implementa los interfaces DataInputy DataOutput, un beneficio lateral es que los streams filtrados tambin funcionan con otros streamsDat aI nput yDat aO ut put incluidos algunos streams de acceso secuencial comoDat aI nput Str eam yDat aO ut put Str eam. El ejemploCheckedI O Test de Escribir Nuestros Propios Streams Filtrados implementa dos streams filtrados,CheckedInputStream yCheckedOutputStream, que calculan un checksum de los datos que son ledos o escritos en el stream. El nuevo ejemplo,CheckedDat aO ut put es una re-escritura deCheckedO ut put St ream-calcula un checksum para los datos escritos en el stream-- pero opera sobre objetos DataOutput en lugar de sobre objetos OutputStream. De forma similarCheckedDat aI nput modificaCheckedI nput St r eam para que ahora funciona sobre objetosDat aI nput en lugar de objetosI nput St r eam. CheckedDataOutputcont ra CheckedOutputStream Echemos un vistazo a las diferencias entreCheckedDat aO ut put yCheckedO ut put St r eam. La primera diferencia es queCheckedDat aO ut putno desciende deFilt erO ut put St ream. En su lugar, implementa el interfaceDat aO ut put.

public class CheckedDataOutput implements DataOutput Nota: Para mantener el ejemplo sencillo, la claseCheckedDat aO ut put realmente proporcionada en esta seccin no est declarada para implementarDataOutput, porque el interface DataOutput especifica demasiados mtodos. Sin embargo, la clase CheckedDataOutput proporcionada en el ejemplo implementa varios mtodos deDat aO ut put para ilustrar como deberan funcionar. Luego,CheckedDataOutput declara una variable privada para contener un objeto DataOutput. private DataOutput out; Este es el objeto en el se escribirn los datos. El constructor paraCheckedDataOutput es diferente del constructor de CheckedOutputStream: CheckedDataOutput se crea sobre un objeto DataOutput en vez sobre un objetoO ut put St r eam. public CheckedDataOutput(DataOutput out, Checksum cksum) { this.cksum = cksum; 29

this.out = out; }Este constructor no llama asuper(out) como haca el constructor de CheckedOutputStream. Esto es porque CheckedDataOutput desciende de Object en vez de la clase stream. Aqu estn las nicas modificaciones echas aCheckedO ut put St r eam para crear un filtro que funcione sobre objetosDat aO ut put. CheckedDataInputcont ra CheckedInputStream CheckedDataInput requiere los mismos cambios que CheckedDataOuput. CheckedDataInput no desciende de FilterInputStream pero implementa el interface DataInput. Nota: Para mantener el ejemplo sencillo, la claseCheckedDataInput realmente proporcionada en esta seccin no est declarada para implementarDataInput,

porque el interfaceDat aI nput especifica demasiados mtodos. Sin embargo, la claseCheckedDat aI nput proporcionada en el ejemplo implementa varios mtodos deDat aI nput para ilustrar como deberan funcionar. CheckedDataInput declara una variable privada para contener un objeto DataInput que lo envuelve. El constructor deCheckedDat aI nput requiere un objetoDat aI nput en vez de un objetoI nput St r eam. Adems de estos cambios, el mtodoread tambin se ha modificado. El CheckedInputStream del ejemplo original implementa dos mtodos read, uno para leer un slo byte y otro para leer un array de bytes. El interfaceDat aI nput teine mtodos que implementan la misma funcionalidad, pero tienen diferentes nombres y firmas de mtodos. As el mtodoread de la claseCheckedDat aI nput tiene nuevos nombres y firmas de mtodos. public byte readByte() throws IOException { byte b = in.readByte(); cksum.update(b); return b; }public void readFully(byte[] b) throws IOException { in.readFully(b, 0, b.length); cksum.update(b, 0, b.length); }public void readFully(byte[] b, int off, int len) throws IOException { in.readFully(b, off, len); cksum.update(b, off, len); 30

} Los Programas Principales Finalmente, este ejemplo tiene dos programas principales para probar los nuevos filtros. CheckedDITest, que ejecuta el filtro sobre ficheros de acceso secuencial (objetos DataInputStreamy DataOutputStream), yCheckedRAFT est, que ejecuta los filtros sobre ficheros de acceso aleatorio (objetosRandom AccessFi les). Estos dos programas se diferencian slo en el tipo del objeto que abren para el filtro. CheckedDITest crea un DataInputStream y un DataOutputStream y usa el filtro checksum sobre ellos, como en el siguiente cdigo: cis = new CheckedDataInput( new DataInputStream(new FileInputStream("farrago.txt")), inChecker); cos = new CheckedDataOutput( new DataOutputStream(new FileOutputStream("outagain.txt")), outChecker); CheckedRAFTest crea dos RandomAccessFiles, uno para leer y uno para escribir, y usa el filtro checksum sobre ellos. cis = new CheckedDataInput( new RandomAccessFile("farrago.txt", "r"), inChecker); cos = new CheckedDataOutput( new RandomAccessFile("outagain.txt", "rw"), outChecker);

Cuando ejecutemos cualquiera de estos programas deberamos ver la siguiente salida: Input stream check sum: 736868089 Output stream check sum: 736868089 Y el Resto... Y el Resto... Adems de las clases e interfaces explicadas en esta leccin,java.io contiene las siguientes clases e interfaces File Representa un fichero del sistema de ficheros nativo. 31 Podemos crear un objetoFile para un fichero del sistema de ficheros nativo y luego consultar en el objeto informacin sobre ese fichero (como su path completo). FileDescriptor Representa un manejador de fichero (o descriptor) para abrir un fichero o un socket. Normalmente no usaremos esta clase. StreamTokenizer Parte el contenido de un stream en tokens. Los Tokens son la unidad ms pequea reconocida por un algoritmo de anlisis de texto (como palabras, smbolos, etc). Se puede usar unStreamTokenizer para analizar un fichero de texto. Por ejemplo, podramos usarlo para dividir un fichero fuente Java en nombres de variables, operadores, etc, o dividir un fichero HTML en etiquetas HTML. FilenameFilter Usado por el mtodo list de la claseFile para determinar qu ficheros se deben mostrar de un directorio. ElFilenam eFi lt er accepta o rechaza ficheros

basndose en su nombre. Podramos usarFilenameF ilt er para implementar unos sencillos patrones de bsqueda de ficheros comof oo*. Tambin podemos encontrar otros streams de entrada y salida en el paquetejava. ut il. zip, incluyendo estos: CheckedInputStreamy CheckedOutputStream Una pareja de streams de entrada y salida que mantiene un checksum de los datos que estn siendo ledos o escritos. DeflaterOutputStreamy InflaterInputStream Comprime o descomprime los datos que estn siendo ledos o escritos. GZIPInputStreamy GZIPOutputStream Lee y escribe datos comprimidos en el formato GZIP. ZipInputStreamy ZipOutputStream Lee y escribe datos comprimidos en el formato ZIP.

Con este programa, se creara un archivo con registros de numero de matricula, nombre y pedir 3 calificaciones para despus calcular el promedio. import java.io.*; import java.util.Scanner; public class Archivos{ public static void main( String args[] )throws IOException{ Scanner leer = new Scanner(System.in); DataOutputStream Archi = null; int i; int matricula=0; String nombre=new String(); int calif1; int calif2; int calif3; double promedio; try{ for (i=0; i<5; i++){ Archi = new DataOutputStream( new FileOutputStream(../Archivo.dat,true) );

System.out.println(Escribe la matricula: ); matricula = leer.nextInt(); System.out.println(Escribe Nombre: ); nombre = leer.next(); System.out.println(Ingrese Calificacion 1: ); calif1 = leer.nextInt(); System.out.println(Ingrese Califiacin 2); calif2 = leer.nextInt(); System.out.println(Ingrese Calificacion 3); calif3 = leer.nextInt(); Archi.writeInt(matricula); Archi.writeUTF(nombre); Archi.writeInt(calif1); Archi.writeInt(calif2); Archi.writeInt(calif3); Archi.close(); } } catch(FileNotFoundException fnfe) {} catch (IOException ioe) {} } } Este otro mostrara lo que hay en el archivo: import java.io.*; public class LeerArchivos{ public static void main( String args[] )throws IOException{ DataInputStream Archi = null; int matricula=0; String nombre=new String(); int calif1; int calif2; int calif3; double promedio; try{ Archi = new DataInputStream( new FileInputStream(../Archivo.dat) ); while (true){ matricula = Archi.readInt(); System.out.println(Matricula: +matricula+ ); nombre = Archi.readUTF(); System.out.println(Nombre: +nombre+ );

calif1= Archi.readInt(); System.out.println(Calificacion 1: +calif1+ ); calif2= Archi.readInt(); System.out.println(Calificacion 2: +calif2+ ); calif3= Archi.readInt(); System.out.println(Calificacion 3: +calif3+ ); System.out.println(n); int suma = calif1 + calif2 + calif3; promedio = suma/3; System.out.println(El promedio es: +promedio+n); } } catch(FileNotFoundException fnfe) {} catch (IOException ioe) {} Archi.close(); } } El proceso de lectura de un archivo de texto es similar a la lectura desde el dispositivo estndar. Creamos un objeto entrada de la clase FileReader en vez de InputStreamReader. El final del archivo viene dado cuando la funcin read devuelve -1. El resto del cdigo es similar.
FileReader entrada=null; StringBuffer str=new StringBuffer(); try { entrada=new FileReader("ArchivoApp2.java"); int c; while((c=entrada.read())!=-1){ str.append((char)c); } }catch (IOException ex) {}

Para mostrar el archivo de texto en la pantalla del monitor, se imprime el contenido del objeto str de la clase StringBuffer.
System.out.println(str);

Una vez concludo el proceso de lectura, es conveniente cerrar el flujo de datos, esto se realiza en una clasula finally que siempre se llama independientemente de que se produzcan o no errores en el proceso de lectura/escritura.
}finally{

if(entrada!=null){ try{ entrada.close(); }catch(IOException ex){} } }

El cdigo completo de este ejemplo es el siguiente:


public class ArchivoApp2 { public static void main(String[] args) { FileReader entrada=null; StringBuffer str=new StringBuffer(); try { entrada=new FileReader("ArchivoApp2.java"); int c; while((c=entrada.read())!=-1){ str.append((char)c); } System.out.println(str); System.out.println("--------------------------------------"); }catch (IOException ex) { System.out.println(ex); }finally{ //cerrar los flujos de datos if(entrada!=null){ try{ entrada.close(); }catch(IOException ex){} } System.out.println("el bloque finally siempre se ejecuta"); } } }

Lectura/escritura
archivo3: ArchivoApp3.java Los pasos para leer y escribir en disco son los siguientes:
1. Se crean dos objetos de las clases FileReader y FileWriter, llamando a los respectivos

constructores a los que se les pasa los nombres de los archivos o bien, objetos de la clase File, respectivamente
entrada=new FileReader("ArchivoApp3.java"); salida=new FileWriter("copia.java");

2. Se lee mediante read los caracteres del flujo de entrada, hasta llegar al final (la

funcin read devuelve entonces -1), y se escribe dichos caracteres en el flujo de salida mediante write.
while((c=entrada.read())!=-1){ salida.write(c); }

3. Finalmente, se cierran ambos flujos llamando a sus respectivas funciones close en

bloques try..catch
entrada.close(); salida.close();

El cdigo completo de este ejemplo que crea un archivo copia del original, es el siguiente
import java.io.*; public class ArchivoApp3 { public static void main(String[] args) { FileReader entrada=null; FileWriter salida=null; { entrada=new FileReader("ArchivoApp3.java"); salida=new FileWriter("copia.java"); int c; while((c=entrada.read())!=-1){ salida.write(c); } }catch (IOException ex) { System.out.println(ex); }finally{ //cerrar los flujos de datos if(entrada!=null){ try{ entrada.close(); }catch(IOException ex){} } if(salida!=null){ try{ salida.close(); }catch(IOException ex){} } System.out.println("el bloque finally siempre se ejecuta"); } } } try

Cuando se trate de leer y escribir datos binarios se sustituye FileReader por FileInputStream y FileWriter por FileOutputStream. De hecho, si se realiza esta sustitucin en el cdigo fuente de este ejemplo, los resultados no cambian.

S-ar putea să vă placă și