I am looking for example code that demonstrates how to create a filter that understands binary data. Links to examples are greatly appreciated.
If you mean examples of FilterInputStream/FilterOutputStream, then you need look no further than the JDK. I'll talk about the input stream variant for the sake of argument, but the same applies to output streams.
Take a look at InflaterInputStream, for example. Look at the arry read() method, and notice how at some point if calls fill(), which in turn reads from the underlying input stream. Then, around that method, it calls into the Inflater to actually turn the buffer of "raw" bytes that it pulled from the underlying stream into the actual bytes that are written to the caller's array.
One thing to consider is that FilterInputStream is a little bit of a waste of space. So long as you can define your InputStream to take another underlying InputStream, and in all the read method(s) you read from that underlying stream (bearing in mind that in theory you only need to define the byte read() method), then specifically making your class extend FilterInputStream doesn't really buy you very much. For example, here's part of the code for an input stream that limits the number of bytes from the underlying stream that it allows the caller to read (in effect, we can "chop up" a stream into several sub-streams, which is useful when reading from archive files, for example):
class LimitedInputStream extends InputStream {
private InputStream in;
private long bytesLeft;
LimitedInputStream(InputStream in, long maxBytes) {
this.in = in;
this.bytesLeft = maxBytes;
}
@Override
public int read() throws IOException {
if (bytesLeft <= 0)
return -1;
int b = in.read();
bytesLeft--;
return b;
}
@Override
public int read(byte b[], int off, int len) throws IOException {
if (bytesLeft <= 0)
return -1;
len = (int) Math.min((long) len, bytesLeft);
int n = in.read(b, off, len);
if (n > 0)
bytesLeft -= n;
return n;
}
// ... missed off boring implementations of skip(), available()..
}
In this case in my application, it really buys me nothing to declare this class as a FilterInputStream-- in effect, it's a choice between wanting to call in.read() or super.read() to get the underlying data...!
For a good example, I'd suggest taking a look at the source code for java.io.DataInputStream
. This class shows you one way to decode primitive types and character strings from "binary" data, from which more complex structures can be produced.
Of course, other applications might choose to use other encodings. For example, the ASN.1 "distinguished encoding rules" are used for Public Key Infrastructure applications. Lucene provides good documentation for its file format, which is designed for compactness.
If you have the Sun JDK, look in its top directory for "src.zip". Most IDEs will show you the source code for the core Java classes if you tell them where to find this file.