Como usar Piped Streams
PipedReader y PipedWriter (y sus correspondientes streams de entrada y salida PipedInputStream y PipedOutputStream) implementan los componentes de entrada y salida de una tubería.
Las tuberías 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 manipulación de strings como ordenación o inversión de texto. Sería bonito que la salida de uno de estos métodos puediera ser usada como entrada del otro para que pudieramos encadenar una serie de llamadas a métodos que realizan un función de gran importancia. Por ejemplo, podríamos invertir todas las palabras de una lista, ordenarlas, y volver a invertirlas para crear una lista de palabrás rítmicas.
Sin los streams de tuberías, el programa debería almacenar los resultados en algún lugar (como en un fichero o en la memoria) entre cada paso, como se ve aquí:
Con los streams de tuberías, la salida de un método 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 usa PipedReader y PipedWriter para conectar la entrada y la salida de sus métodos reverse y sort para crear una lista de palabras rítmicas. Este programa se compone de varias clases. Esta sección muestra y explica sólo los elementos del programa que leen y escriben en las tuberías. Sigue los siguientes enlaces al código para ver el programa completo.
Primero, echemos un vistazo a la secuencia de llamada de los métodos reverse y sort desde el método main en la clase
RhymingWords.
FileReader words = new FileReader("words.txt");
Reader rhymingWords = reverse(sort(reverse(words)));
La llamada más interna a reverse toma un FileReader abierto sobre el fichero words.txt que contiene una lista de palabras. El valor devuelto por reverse se pasa a sort, cuyo valor de retorno es pasado a otra llamada a reverse.
Echemos un vistazo al método reverse; el método sort es similiar y lo entenderemos una vez que comprendamos reverse.
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 de reverse crean los dos puntos finales de una tubería --un PipedWriter y un PipedReader-- y los conecta construyendo el PipedReader "sobre" el PipedWriter.
Cualquier cosa escrita en el PipedWriter puede ser leída desde el PipedReader.
Las formas de conexión de tuberías se ilustran aquí:.
reverse arranca un ReverseThread que escribe su salida en el PipedWriter y devuelve el PipedReader al llamador.
Entonces el llamador preprara un thread de ordenación para leerla.
El método sort es exactamente lo mismo, excepto en que crea y arranca un SortThread.
Usar Streams para Envolver otros Streams
El método reverse contiene algún código interesante; en particular estas dos sentencias:
BufferedReader in = new BufferedReader(source);
...
PrintWriter out = new PrintWriter(pipeOut);
La primera línea abre un BufferedReader sobre source, el argumento a invertir (un Reader).
Esto esencialmente "envuelve" source en un BufferedReader.
El programa lee desde el BufferedReader, que a su vez lee desde source.
El programa hace esto para poder usar el método de conveniencia readLine de
BufferedReader.
De forma similar, el PipedWriter es envuelto en un PrintWriter para que el programa pueda usar el método de conveniencia println de PrintWriter.
Frecuentemente veremos estreams envueltos de esta forma para así combinar las distintas características de varios streams.
|
Intenta esto:
Escribe otra versión de este programa que use inputstreams y outputstreams en vez de readers y writers.
Aquí puedes ver las soluciones:
|