Previous | Next | Trail Map | Essential Java Classes | Reading and Writing (but no 'rithmetic)

How to Use Pipe Streams

PipedReader(in the API reference documentation) and PipedWriter(in the API reference documentation) (and their input and output stream counterparts PipedInputStream(in the API reference documentation) and PipedOutputStream(in the API reference documentation)) implement the input and output components of a pipe. Pipes are used to channel the output from one program (or thread) into the input of another. Why is this useful?

Consider a class that implements various string manipulation utilities such as sorting and reversing text. It would be nice if the output of one of these methods could be used as the input for another so that you could string a series of method calls together to perform some higher-order function. For example, you could reverse each word in a list, sort the words, and then reverse each word again to create a list of rhyming words.

Without pipe streams, the program would have to store the results somewhere (such as in a file or in memory) between each step, as shown here:

With pipe streams, the output from one method could be piped into the next, as shown in this figure:
Next, we investigate a program that implements what's represented by the diagram in the previous figure. This program uses PipedReader and PipedWriter to connect the input and output of its reverse and sort methods in order to create a list of rhyming words. Several classes make up this program. This section shows and discusses only the elements of the program that read from and write to the pipes. Follow the code links presented here to see the whole program.

First, let's look at the calling sequence of the reverse and sort methods from the main method in the RhymingWords class:

FileReader words = new FileReader("words.txt");
Reader rhymingWords = reverse(sort(reverse(words)));
The innermost call to reverse takes a FileReader opened on the file words.txt that contains a list of words. The return value of reverse is passed to sort, whose return value is then passed to another call to reverse.

Let's look at the reverse method; the sort method is similar and you will understand it once you understand 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;
}
The bold statements in reverse create both ends of a pipe--a PipedWriter and a PipedReader-- and connects them by constructing the PipedReader "on" the PipedWriter. Whatever's written to the PipedWriter can be read from the PipedReader. The connection forms a pipe, as illustrated here:
reverse starts a ReverseThread that writes its output to the PipedWriter and then returns the PipedReader to the caller. The caller then arranges for a sorting thread to read from it. The sort method is exactly the same, except that it creates and starts a SortThread.

Using Streams to Wrap Other Streams

The reverse method contains some other interesting code; in particular, these two statements:
BufferedReader in = new BufferedReader(source);
...
PrintWriter out = new PrintWriter(pipeOut);
The first line opens a BufferedReader on source, the argument to reverse (a Reader). This essentially "wraps" source in a BufferedReader. The program reads from the BufferedReader, which in turn reads from source. The program does this so that it can use BufferedReader's convenient readLine method. Similarly, the PipedWriter is wrapped in a PrintWriter so that the program can use PrintWriter's convenient println method. You will often see streams wrapped in this way so as to combine the various features of the many streams.

Try this: Write another version of this program that uses input streams and output streams in place of readers and writers. See for the solution.


Previous | Next | Trail Map | Essential Java Classes | Reading and Writing (but no 'rithmetic)