Streams are primarily intended for data that can be read as pure bytesbasically, byte data and numeric data encoded as binary numbers of one sort or another. Streams are specifically not intended for reading and writing text, including both ASCII text, such as "Hello World," and numbers formatted as text, such as "3.1415929". For these purposes, you should use readers and writers.
Input and output streams are fundamentally byte-based. Readers and writers are based on characters, which can have varying widths depending on the character set. For example, ASCII and Latin-1 use 1-byte characters. UTF-32 uses 4-byte characters. UTF-8 uses characters of varying width (between one and four bytes). Since characters are ultimately composed of bytes, readers take their input from streams. However, they convert those bytes into chars according to a specified encoding format before passing them along. Similarly, writers convert chars to bytes according to a specified encoding before writing them onto some underlying stream.
The java.io.Reader and java.io.Writer classes are abstract superclasses for classes that read and write character-based data. The subclasses are notable for handling the conversion between different character sets. The core Java API includes nine reader and eight writer classes, all in the java.io package:
For the most part, these classes have methods that are extremely similar to the equivalent stream classes. Often the only difference is that a byte in the signature of a stream method becomes a char in the signature of the matching reader or writer method. For example, the java.io.OutputStream class declares these three write( ) methods:
public abstract void write(int i) throws IOException public void write(byte data) throws IOException public void write(byte data, int offset, int length) throws IOException
The java.io.Writer class, therefore, declares these three write( ) methods:
public void write(int i) throws IOException public void write(char data) throws IOException public abstract void write(char data, int offset, int length) throws IOException
As you can see, the signatures match except that in the latter two methods the byte array data has changed to a char array. There's also a less obvious difference not reflected in the signature. While the int passed to the OutputStream write( ) method is reduced modulo 256 before being output, the int passed to the Writer write( ) method is reduced modulo 65,536. This reflects the different ranges of chars and bytes.
java.io.Writer also has two more write( ) methods that take their data from a string:
public void write(String s) throws IOException public void write(String s, int offset, int length) throws IOException
Because streams don't know how to deal with character-based data, there are no corresponding methods in the java.io.OutputStream class.
Streams in Memory
The File System
Working with Files
File Dialogs and Choosers
Character Sets and Unicode
Readers and Writers
Formatted I/O with java.text
The Java Communications API
The J2ME Generic Connection Framework