Low-level and High-level Character Streams

To read and write data in binary format, we have FileInputStream/FileOutputStream (low-level streams) and DataInputStream/DataOutputStream (high-level streams). To read data in text format, Java offers so-called reader and writer streams. Note that some authors do not refer to readers and writers as streams. All the classes corresponding to reader and writer streams are subclasses of the Reader and Writer classes and are used to read character streams. Subclasses of Reader and Writer implement specialized streams and are divided into two categories: those that read characters from or write characters to data devices directly (low-level streams) and those that are attached to the low-level streams and perform some kind of processing on the data (high-level streams).

 

1. Low-Level Readers and Writers

The low-level reader streams read data and return it in characters, and low-level output streams accept data as characters and write the output in characters. Two examples of low-level reader and writer streams are FileReader and FileWriter.

1.1 FileReader Class

The FileReader class is meant for reading text files, because it reads a stream of characters. When we instantiate the FileReader class, an opaque connection is created to the specified file, and this connection is represented by an object of the FileDescriptor class. We can specify the file to which we want to create the connection either by specifying the file directly or by specifying the FileDescriptor object. We can create a stream connection only with a regular file, and not with a directory. An IOException is thrown if the specified file is a directory rather than a regular file, if it does not exist and cannot be created, or if it cannot be accessed for some reason. The signature of the FileReader constructors with the File or String parameter follows:

public FileReader(…) throws IOException; 

 

The corresponding commonly used constructors for FileReader are described below:

Constructor Summary

FileReader(File file)
          Creates a new FileReader, given the File to read from.

FileReader(FileDescriptor fd)
          Creates a new FileReader, given the FileDescriptor to read from.

FileReader(String fileName)
          Creates a new FileReader, given the name of the file to read from.

 

After we create an instance of the FileReader class, we can use it to perform operations such as reading a single character, an array of characters, or a part of an array of characters by invoking the following methods:

  • int read() throws IOException: Returns the next character of data, or -1 if the end of the file is reached
  • int read(char[] cbuf) throws IOException: Reads characters from the stream into the array cbuf, and returns the number of characters read, or -1 if the end of the file is reached
  • int read(char[] cbuf, int offset, int len) throws IOException: Reads up to a total of

len characters (starting from offset) into the array cbuf, and returns the number of chars read, or –1 if the end of file is reached

  • void close(): Closes the input stream and releases any system resources assigned to the stream

 

1.2 FileWriter Class

The FileWriter class is meant for writing streams of characters into files. When we instantiate the FileWriter class, an opaque connection is created to the specified file, and this connection is represented by an object of the FileDescriptor class. Just as with FileReader, we can specify the file to which we want to create a connection either by specifying the file directly or by specifying the FileDescriptor object. Note that we can create a stream connection only with a regular file, and not with a directory. An IOException is thrown if the specified file is a directory rather than a regular file, if it does not exist and cannot be created, or if it cannot be accessed to write for some reason. The signature of the FileWriter class constructors with the File or String parameter follows:

public FileWriter(…) throws IOException;

The corresponding commonly used constructors for FileWriter are described below:

Constructor Summary

FileWriter(File file)
          Constructs a FileWriter object given a File object.

FileWriter(File file, boolean append)
          Constructs a FileWriter object given a File object.

FileWriter(FileDescriptor fd)
          Constructs a FileWriter object associated with a file descriptor.

FileWriter(String fileName)
          Constructs a FileWriter object given a file name.

FileWriter(String fileName, boolean append)
          Constructs a FileWriter object given a file name with a boolean indicating whether or not to append the data written.

 

After we create an instance of the FileWriter class, we can use it to perform operations such as writing a single character, an array of characters, or a part of an array of characters by invoking the following methods:

  • void write(int c) throws IOException: Writes the passed-in single character to the stream
  • void write(char[] ch) throws IOException: Writes ch.length number of characters from the passed-in array to the stream
  • void write(String str) throws IOException: Writes the passed-in string to the stream
  • void write(char[] cbuf, int offset, int len) throws IOException: Writes up to a total of len characters (starting from offset) from the passed in array to the stream
  • void write(String str, int offset, int len) throws IOException: Writes up to a total of

len characters (starting from offset) from the passed-in string to the stream

  • void flush() throws IOException: Flushes the stream, which means the remaining

(buffered) data that we have written to the stream is sent out to the file before closing

  • void close(): Closes the output stream and releases any system resources assigned to the stream

 

 

2. High-Level Readers and Writers

As we know, we can use DataInputStream and DataOutputStream to read and write the primitive types in binary format. Similarly, we can read and write characters in character streams in big chunks (buffers) and in text format by using the BufferedReader and BufferedWriter classes, respectively. We can read and write primitive data types (rather than bytes) by using DataInputStream and DataOutputStream. But using BufferedReader and BufferedWriter classes we can read and write data in blocks to minimize I/O overhead. These classes are chained to low-level streams such as FileReader and FileWriter.

The BufferedReader class has the following constructors:

BufferedReader(Reader in);
BufferedReader(Reader in, int size);

The size specifies the buffer size. If the buffer size is not specified, use default value.

 

Similarly, the following are the constructors for the BufferedWriter class:

BufferedReader(Writer out);
BufferedReader(Writer out, int size);

Note that theses constructors do not throw any exception. Because FileReader and FileWriter are subclasses of Reader and Writer, respectively, their objects can also be passed in to the BufferedReader and BufferedWriter constructors.

 

In the next section, we will talk about the Classes and Interfaces of Java I/O API.