Binary versus Character Streams
If we are working with binary data such as images and sounds, we need to use binary mode files. For other purposes, we would use character streams, as in the reader and writer classes described earlier. These reader/writer classes offer us the following benefits:
They handle any character in the Unicode character set; the byte streams are limited to ISO Latin-1 eight-bit bytes.
Programs that use character streams can easily be internationalized because they do not depend on a specific character encoding.
Because character stream classes use internal buffering, inherently they are more efficient than byte streams.
In general, use the FileInputStream and FileOutputStream classes to read and write binary data from and to image files, sound files, video files, configuration files, and so on. These classes can also be used to read/write ASCII-based text files. To read/write modern Unicode-based text files, use the FileReader and FileWriter classes.
Let’s examine this line of code carefully
BufferedReader reader = new BufferedReader(new FileReader("filename"));
Here we saw how a BufferedReader instance is opened on top of a FileReader object. This is called wrapping or chaining streams. Very rarely, a program uses a single stream object. Generally, several stream objects (in a series) are chained to process the data more efficiently. The Java I/O libraries provide several such wrappings. The wrappings help in processing and managing the data more efficiently by providing the additional convenience methods in the subclasses. Connecting several stream classes together helps in getting the data in the required format. Each class performs a specific task on the data and forwards it to the next class in the chain. A typical example of this could be a data-backup utility. Such a program would chain several streams to compress, encrypt, transmit, receive, and finally store the data in a remote file. Adjoining figure shows one such wrapping for an input stream
· Here, we first open the FileInputStream on a physical data source.
· The output of this is buffered in the BufferedInputStream object.
· We wrap this with a DataInputStream for convenient handling of primitive data types.
· The DataInputStream class provides several read methods, such as readByte, readChar, readDouble, and so on, that operate on primitive data types.
A similar wrapping is provided for writer classes as shown in the following figure:
· In this case, the program writes data to a DataOutputStream by using its write methods that accept primitive data types.
· The data written is buffered in a BufferedOutputStream object for efficient disk writing.
· Finally, the data is written out to a physical device using the FileOutputStream object