Chapter 15. Readers and Writers

A language that supports international text must separate the reading and writing of raw bytes from the reading and writing of characters, since in an international system they are no longer the same thing. Classes that read characters must be able to parse a variety of character encodings, not just ASCII, and translate them into the language’s native character set. Classes that write characters must be able to translate the language’s native character set into a variety of formats and write those. In Java this task is performed by the Reader and Writer classes.

You’re probably going to experience a little déjà vu. The java.io.Writer class is modeled on the java.io.OutputStream class. The java.io.Reader class is modeled on the java.io.InputStream class. The names and signatures of the members of the Reader and Writer classes are similar (sometimes identical) to the names and signatures of the members of the InputStream and OutputStream classes. The patterns these classes follow are similar as well. Filtered input and output streams are chained to other streams in their constructors. Similarly, filtered readers and writers are chained to other readers and writers in their constructors. InputStream and OutputStream are abstract superclasses that identify common functionality in the concrete subclasses. Likewise, Reader and Writer are abstract superclasses that identify common functionality in the concrete subclasses. The difference between readers and writers and input and output streams is that streams are fundamentally byte based, while readers and writers are fundamentally character based. Where an input stream reads a byte, a reader reads a character; where an output stream writes a byte, a writer writes a character.

While bytes are a more or less universal concept, characters are not. As you learned in the last chapter, the same character can be encoded differently in different character sets. Different character sets encode different characters. Characters can even have different widths in different character sets. For example, ASCII and ISO Latin-1 use one-byte characters. Unicode uses two-byte characters. UTF-8 uses characters of varying width between one and three bytes. Concrete subclasses of the Reader and Writer classes convert between different character sets and Java’s internal Unicode character set.

The java.io.Writer Class

The Writer class is abstract, just like OutputStream is abstract. You won’t have any pure instances of Writer that are not also instances of some concrete subclass of Writer. However, many of the subclasses of Writer differ primarily in the targets of the text they write, just as many concrete subclasses of OutputStream differ only in the targets of the data they write. Most of the time you don’t care about the difference between FileOutputStream and ByteArrayOutputStream. Similarly, most of the time you won’t care about the differences between FileWriter and StringWriter. You’ll just use the methods of the common superclass, java.io.Writer.

You use a writer almost exactly as you use an output stream. Rather than writing bytes, you write chars. The write() method writes a subarray from the char array text starting at offset and continuing for length characters:

public abstract void write(char[] text, int offset, int length) 
  throws IOException

For example, given some Writer object w, you can write the string Testing 1-2-3 like this:

char[] test = {'T', 'e', 's', 't', 'i', 'n', 'g', ' ', 
               '1', '-', '2', '-', '3'};
w.write(test, 0, test.length);

This method is abstract. Concrete subclasses that convert chars into bytes according to a specified encoding and write those bytes onto an underlying stream must override this method. An IOException may be thrown if the underlying stream’s write() method throws an IOException. You can also write a single character, an entire array of characters, a string, or a substring:

public void write(int c) throws IOException
public void write(char[] text) throws IOException
public void write(String s) throws IOException
public void write(String s, int offset, int length) throws IOException

The default implementations of these four methods convert their first argument into an array of chars and pass that to write(char[] text, int offset, int length). Specific subclasses may provide more efficient implementations of these methods.

Note

This is one of the few instances where the general structure of the Writer and the OutputStream classes diverge, though not in a very significant way. In OutputStream the fundamental, abstract method that must be overridden by subclasses is the write() method that writes a single byte. OutputStream’s multibyte write() methods are implemented in terms of the single-byte write() method, whereas Writer’s single-character write() method is implemented in terms of a multicharacter write() method.

Like output streams, writers may be buffered, precisely because their underlying output stream is buffered. To force the write to take place, call flush():

public abstract void flush() throws IOException

The close() method closes the writer and releases any resources associated with it:

public abstract void close() throws IOException

This flushes the writer, then closes the underlying output stream.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.160.142