Filter Streams
InputStream
and OutputStream
are fairly raw classes. They read and write bytes singly or in groups, but that's all. Deciding what those bytes mean-whether they're integers or IEEE 754 floating point numbers or Unicode text-is completely up to the programmer and the code. However, there are certain extremely common data formats that can benefit from a solid implementation in the class library. For example, many integers passed as parts of network protocols are 32-bit big-endian integers. Much text sent over the Web is either 7-bit ASCII, 8-bit Latin-1, or multi-byte UTF-8. Many files transferred by FTP are stored in the zip format. Java provides a number of filter classes you can attach to raw streams to translate the raw bytes to and from these and other formats. The filters come in two versions: the filter streams and the readers and writers. The filter streams still work primarily with raw data as bytes: for instance, by compressing the data or interpreting it as binary numbers. The readers and writers handle the special case of text in a variety of encodings such as UTF-8 and ISO 8859-1. Filter streams are placed on top of raw streams such as a TelnetInputStream
or a FileOutputStream
or other filter streams. Readers and writers can be layered on top of raw streams, filter streams, or other readers and writers. However, filter streams cannot be placed on top of a reader or a writer, so we'll start with filter streams and address readers and writers in the next section. Filters are organized in a chain, as shown in Screenshot-2. Each link in the chain receives data from the previous filter or stream and passes the data along to the next link in the chain. In this example, a compressed, encrypted text file arrives from the local network interface, where native code presents it to the undocumented TelnetInputStream
. A BufferedInputStream
buffers the data to speed up the entire process. A CipherInputStream
decrypts the data. A GZIPInputStream
decompresses the deciphered data. An InputStreamReader
converts the decompressed data to Unicode text. Finally, the text is read into the app and processed.
Screenshot-2. The flow of data through a chain of filters

Every filter output stream has the same Filters are connected to streams by their constructors. For example, the following code fragment buffers input from the file data.txt. First, a From this point forward, it's possible to use the After these two lines execute, there's no longer any way to access the underlying file input stream, so you can't accidentally read from it and corrupt the buffer. This example works because it's not necessary to distinguish between the methods of Although these statements can get a little long, it's easy to split the statement across several lines, like this:
Connection is permanent. Filters cannot be disconnected from a stream. There are times when you may need to use the methods of multiple filters in a chain. For instance, if you're reading a Unicode text file, you may want to read the byte order mark in the first three bytes to determine whether the file is encoded as big-endian UCS-2, little-endian UCS-2, or UTF-8, and then select the matching write( )
, close( )
, and flush( )
methods as java.io.OutputStream
. Every filter input stream has the same read( )
, close( )
, and available( )
methods as java.io.InputStream
. In some cases, such as BufferedInputStream
and BufferedOutputStream
, these may be the only methods they have. The filtering is purely internal and does not expose any new public interface. However, in most cases, the filter stream adds public methods with additional purposes. Sometimes these are intended to be used in addition to the usual read()
and write( )
methods, like the unread( )
method of PushbackInputStream
. At other times, they almost completely replace the original interface. For example, it's relatively rare to use the write()
method of PrintStream
instead of one of its print( )
and println( )
methods.
Chaining Filters Together
FileInputStream
object fin
is created by passing the name of the file as an argument to the FileInputStream
constructor. Then, a BufferedInputStream
object bin
is created by passing fin
as an argument to the BufferedInputStream
constructor:
FileInputStream fin = new FileInputStream("data.txt");
BufferedInputStream bin = new BufferedInputStream(fin);
read( )
methods of both fin
and bin
to read data from the file data.txt. However, intermixing calls to different streams connected to the same source may violate several implicit contracts of the filter streams. Most of the time, you should only use the last filter in the chain to do the actual reading or writing. One way to write your code so that it's at least harder to introduce this sort of bug is to deliberately lose the reference to the underlying input stream. For example:
InputStream in = new FileInputStream("data.txt");
in = new BufferedInputStream(in);
InputStream
and those of BufferedInputStream
. BufferedInputStream
is simply used polymorphically as an instance of InputStream
in the first place. In cases where it is necessary to use the additional methods of the filter stream not declared in the superclass, you may be able to construct one stream directly inside another. For example:
DataOutputStream dout = new DataOutputStream(new BufferedOutputStream( new FileOutputStream("data.txt")));
DataOutputStream dout = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream("data.txt")
)
);
Reader
filter for the encoding. Or, if you're connecting to a web server, you may want to read the header the server sends to find the Content-encoding
and then use that content encoding to pick the right Reader
filter to read the body of the response. Or perhaps you want to send floating point numbers across a network connection using a DataOutputStream
and then retrieve a MessageDigest
from the DigestOutputStream
that the DataOutputStream
is chained to. In all these cases, you need to save and use references to each of the underlying streams. However, under no circumstances should you ever read from or write to anything other than the last filter in the chain.Buffered Streams