| Input and Output Streams

## Using Streams to Implement Pipes

> The java.io package contains two classes, PipedInputStream and PipedOutputStream, that 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.

> Piped input and output streams are convenient for methods that produce output to be used as input by someone else. For example, suppose that you are writing a class that implements various text 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. Thus you could string a series of these methods together to perform some function. The pipe shown here uses reverse, sort, and reverse on a list of words to create a list of rhyming words:

> Without piped streams, you would have to create a temporary file between each step:

> Let's look at a program that implements the reverse and sort methods described above using piped streams, and then uses the reverse and sort methods in the pipe shown above to generate a list of rhyming words.

> First, the RhymingWords class contains three methods: `main()`, `reverse()`, and `sort()`. The `main()` method provides the code for the main program, which opens an input file, uses the other two methods to reverse, sort, and reverse the words in the input file, and then writes the results to the standard output stream.

> `reverse()` and `sort()`are designed to be used in a pipe. Both `reverse()` and `sort` read data from an InputStream, process it (either reversing the strings or sorting them), and produce a PipedInputStream suitable for another method to read. Let's look in detail at `reverse()`; the `sort()` method is very similar to `reverse()` and doesn't warrant its own discussion.

> >     public static InputStream reverse(InputStream source) {
> >         PipedOutputStream pos = null;
> >         PipedInputStream pis = null;

> >         try {
> >             DataInputStream dis = new DataInputStream(source);

> >             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;
> >     }

> The `reverse()` method takes an InputStream called `source` that contains a list of strings to be reversed. `reverse()` maps a DataInputStream onto the `source` InputStream so that it can use the DataInputStream's `readLine()` method to read each line from the file. (DataInputStream is a filtered stream which must be attached to (mapped onto) an InputStream whose data is to be filtered when read. Working with Filtered Streams talks about this.)

> Next `reverse()` creates a PipedOutputStream and connects a PipedInputStream to it. Remember that a PipedOutputStream must be connected to a PipedInputStream. Then `reverse()` maps a PrintStream onto the PipedOutputStream so that it can use the PrintStream's `println()` method to write strings to the PipedOutputStream.

> Now `reverse()` creates a WriteReversedThread thread object, hands it two streams--the PrintStream attached to the PipedOutputStream and the DataInputStream attached to `source`--and starts it. The WriteReversedThread object read words from the DataInputStream, reverses them, and writes the output to the PrintStream (thereby writing the output to a pipe). The thread object allows each end of the pipe to run independently of one another and prevents the `main()` method from locking up if one end of a pipe blocks waiting for an I/O call to complete.

> Here's the `run` method for 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);
> >             }
> >         }
> >     }

> Because the PipedOutputStream is connected to the PipedInputStream, all data written to the PipedOutputStream flows into the PipedInputStream. The data can be read from the PipedInputStream by another program or thread. `reverse()` returns the PipedInputStream for use by the calling program.

> The `sort()` method follows the same pattern:

> - Open piped output stream.
> - Connect piped input stream to it.
> - Using a SortThread object, read from the piped input stream and write to the piped output stream, which is the piped input stream for someone else.
> - Hand the now-full piped input stream to someone else to read.
> Calls to `reverse()` and `sort()` can be cascaded together so that the output from one method can be the input for the next method. In fact, the `main()` method does just that. It cascades calls to `reverse()`, `sort()`, and then `reverse()` to generate a list of rhyming words:

> >     InputStream rhymedWords = reverse(sort(reverse(words)));

> When you run RhymingWords on this file of words you will see this output:

> >     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
> >     security

> If you look closely you can see that "rhyming" words such as environment, development, argument, and component are grouped together.

> #### See Also

> > java.io.PipedInputStream
> > java.io.PipedOutputStream

| Input and Output Streams