Los canales de entrada y salida para tuberías son convenientes para métodos que producen una salida para ser utiliza como entrada de otro método. Por ejemplo, supongamos que estamos; escribiendo una clase que implementa varias utilidades de texto, como la ordenación y la inversión del texto. Seria bonito que la salida de uno de esos métodos pudiera utilizarse como la entrada de otro. Así podríamos concatenar una serie de esos métodos para realizar alguna función. La tubería utilizada aquí utiliza los métodos reverse, sort y reverse sobre una lista de palabras para ordenarla de forma rítmica:
Sin los canales de tuberías, tendríamos que crear un fichero temporal entre cada uno de los pasos. Echemos un vistazo al programa que implementa los métodos reverse y sort descritos arriba utilizando los canales de tuberías, y luego utiliza estas métodos para mostrar la tubería anterior para generar una lista de palabras rítmicas.
Primero, la clase RhymingWords contiene tres métodos: main(), reverse(), y sort(). El método main() proporciona el código para el programa principal, el cual abre un fichero de entrada, utiliza los otros dos métodos para invertir, ordenar y volver a invertir las palabras del fichero de entrada, y escribe la salida en el canal de salida estandard.
reverse() y sort() están diseñados para ser utilizados en una tubería.
Estos dos métodos leen datos desde un InputStream, los procesan (invirtiendo las cadenas u ordenandolas), y producen un PipedInputStream adecuado para que otro método pueda leerlo.
Echemos un vistazo en más detalle al método reverse(); sort es muy similar al anterior, por eso no merece la pena explicarlo.
public static InputStream reverse(InputStream source) {
PipedOutputStream pos = null;
PipedInputStream pis = null;
try {
DataInputStream dis = new DataInputStream(source);
String input;
pos = new PipedOutputStream();
pis = new PipedInputStream(pos);
PrintStream ps = new PrintStream(pos);
new WriteReversedThread(ps, dis).start();
} catch (Exception e) {
System.out.println("RhymingWords reverse: " + e);
}
return pis;
}
El método reverse() toma un InputStream llamado source que contiene la lista de cadenas a invertir. reverse() proyecta un DataInputStream sobre el InputStream source para que pueda utilizar el método readLine() de DataInputStream para leer una a una las líneas del fichero. (DataInputStream es un canal filtrado que debe ser añadido a un InputStream (o proyectado sobre) cuyos datos se deben filtrar mientras son leidos.Trabajar con Canales Filtrados explica más cosas sobre esto.)
Luego reverse() crea un PipedOutputStream y le conecta un PipedInputStream. Recuerda que un PipedOutputStream debe estar conectado a un PipedInputStream. Después, reverse() proyecta un PrintStream sobre el PipedOutputStream para que pueda utilizar el método println() de PrintStream para escribir las cadenas en el PipedOutputStream.
Ahora reverse() crea un objeto thread WriteReversedThread, que cuelga de dos canales -- el PrintStream añadido a PipedOutputStream y el DataInputStream añadido a source-- y lo arranca. El objeto WriteReversedThread lee las palabras desde el DataInputStream, las invierte y escribe la salida en el PrintStream (por lo tanto, escribe la salida en una tubería). El objeto thread permite que cada final de la tubería se ejecute independientemente y evita que el método main() se bloquee si una de las tuberías se bloquea mientras espera a que se complete una llamada a I/O.
Aquí tienes el método run de WriteReversedThread:
public void run() {
if (ps != null && dis != null) {
try {
String input;
while ((input = dis.readLine()) != null) {
ps.println(reverseIt(input));
ps.flush();
}
ps.close();
} catch (IOException e) {
System.out.println("WriteReversedThread run: " + e);
}
}
}
Como el PipedOutputStream está conectado al PipedInputStream, todos los datos escritos en el PipedOutputStream caen dentro del PipedInputStream. Los datos pueden ser leidos desde PipedInputStream por cualquier otro programa o thread. reverse() devuelve el PipedInputStream para que lo utilice el programa llamador.
El método sort() sigue el siguiente patrón:
InputStream rhymedWords = reverse(sort(reverse(words)));Cuando ejecutes RhymingWords con este fichero de texto verás la siguiente salida:
Java interface image language communicate integrate native string network stream program application animation exception primer container user graphics threads tools class bolts nuts object applet environment development argument component input output anatomy securitySi miras detenidamente puedes ver que las palabras rítmicas como environment, development, argument, y component están agrupadas juntas.