Caution
Since the backslash character is the escape character in Java strings, be sure to use \\ for Windows-style path names (for example,
C:\\Windows\\win.ini). In Windows, you can also use a single forward slash (C:/Windows/win.ini) because most Windows
file-handling system calls will interpret forward slashes as file separators. However, this is not recommended—the behavior of the
Windows system functions is subject to change. Instead, for portable programs, use the file separator character for the platform on which
your program runs. It is available as the constant string java.io.File.separator.
Like the abstract InputStream and OutputStream classes, these classes support only reading and writing at the byte level. That is, we can
only read bytes and byte arrays from the object fin.
byte b = (byte) fin.read();
As you will see in the next section, if we just had a DataInputStream, we could read numeric types:
DataInputStream din = . . .;
double s = din.readDouble();
But just as the FileInputStream has no methods to read numeric types, the DataInputStream has no method to get data from a file.
Java uses a clever mechanism to separate two kinds of responsibilities. Some streams (such as the FileInputStream and the input stream
returned by the openStream method of the URL class) can retrieve bytes from files and other more exotic locations. Other streams (such as the
DataInputStream and the PrintWriter) can assemble bytes into more useful data types. The Java programmer has to combine the two.
For example, to be able to read numbers from a file, first create a FileInputStream and then pass it to the constructor of a
DataInputStream.
Click here to view code image
FileInputStream fin = new FileInputStream("employee.dat");
DataInputStream din = new DataInputStream(fin);
double s = din.readDouble();
If you look at Figure 1.1 again, you can see the classes FilterInputStream and FilterOutputStream. The subclasses of these classes
are used to add capabilities to raw byte streams.
You can add multiple capabilities by nesting the filters. For example, by default streams are not buffered. That is, every call to read asks the
operating system to dole out yet another byte. It is more efficient to request blocks of data instead and store them in a buffer. If you want buffering
and the data input methods for a file, you need to use the following rather monstrous sequence of constructors:
DataInputStream din = new DataInputStream(
new BufferedInputStream(
new FileInputStream("employee.dat")));
Notice that we put the DataInputStream last in the chain of constructors because we want to use the DataInputStream methods, and we
want them to use the buffered read method.
Sometimes you’ll need to keep track of the intermediate streams when chaining them together. For example, when reading input, you often need
to peek at the next byte to see if it is the value that you expect. Java provides the PushbackInputStream for this purpose.
Click here to view code image
PushbackInputStream pbin = new PushbackInputStream(
new BufferedInputStream(
new FileInputStream("employee.dat")));
Now you can speculatively read the next byte
int b = pbin.read();
and throw it back if it isn’t what you wanted.
if (b != '<') pbin.unread(b);
However, reading and unreading are the only methods that apply to a pushback input stream. If you want to look ahead and also read numbers,
then you need both a pushback input stream and a data input stream reference.
DataInputStream din = new DataInputStream(
pbin = new PushbackInputStream(
new BufferedInputStream(
new FileInputStream("employee.dat"))));
Of course, in the stream libraries of other programming languages, niceties such as buffering and lookahead are automatically taken care of, so it
is a bit of a hassle to resort, in Java, to combining stream filters. However, the ability to mix and match filter classes to construct truly useful
sequences of streams does give you an immense amount of flexibility. For example, you can read numbers from a compressed ZIP file by using
the following sequence of streams (see Figure 1.4):
Click here to view code image
ZipInputStream zin = new ZipInputStream(new FileInputStream("employee.zip"));
DataInputStream din = new DataInputStream(zin);