Read and write data with Java's I/O streams
Streams
All of Java's I/O facilities are based on streams that represent flowing
sequences of characters or bytes. Java's I/O streams provide standardized ways
to read and write data. Any object representing a mutable data source in Java
exposes methods for reading and writing its data as a stream.
Java.io is
the main package for most stream-oriented I/O classes. This package presents two
abstract classes, InputStream and OutputStream. All other
stream-oriented I/O classes extend these base classes.
The java.io
package exposes a number of classes and interfaces that provide useful
abstractions on top of the character and byte reading and writing operations
defined by InputStream and OutputStream. For example, the
ObjectInputStream class provides methods that allow you to read data from
a stream as a Java object, and the ObjectOutputStream provides methods
that allow you to write data to a stream as a Java object.
Optimized reading and writing
JDK 1.1 added a collection of reader and writer classes that provide more useful
abstractions and improved I/O performance than the existing streams classes. For
instance, the BufferedReader and BufferedWriter classes are
provided to read text from and write text to character-based input streams and
output streams. The BufferedReader class buffers characters to more
efficiently read characters, arrays, and lines. The BufferedWriter class
buffers characters to more efficiently write characters, arrays, and strings.
The size of the buffer used by the BufferedReader and
BufferedWriter classes can be set as desired.
Reader and writer
classes provided by the Java I/O Framework include the LineNumberReader
class, the CharArrayReader class, the FileReader class, the
FilterReader class, the PushbackReader class, the
PipedReader class, and the StringReader class, among others. These
classes are wrappers on top of the InputStream and OutputStream
classes and thus provide methods that are similar to InputStream and
OutputStream. However, these classes provide more efficient and useful
abstractions for reading and writing specific objects, such as files, character
arrays, and strings.
Reading data
An input stream is typically opened for you automatically when it is retrieved from the corresponding data source object or when you construct one of the reader objects. For example, to open the input stream for a file, we pass the name of the file into a java.io.FileReader object's constructor as follows:
java.io.FileReader fileReader = new java.io.FileReader("/home/me/myfile.txt");
To read the next available byte of data from a FileReader's underlying input stream, use the read method with no parameters. The snippet in Listing A reads text from a file, one character at a time, and writes it to System.out.
To read a given number of bytes from an input stream into a char array, use the read method with one char[] parameter. The length of the array is used to determine the number of characters to read. Listing B demonstrates this technique.
To close an input stream and release any system resources used by the stream, use the close method as follows:
fileReader.close();
Writing data
Like an input stream, an output stream is typically opened for you automatically when it is retrieved from the corresponding data source object or when you construct one of the writer objects. For example, to open the output stream for a file, we pass the name of the file into a java.io.FileWriter object's constructor as follows:
java.io.FileWriter fileWriter = new java.io.FileWriter("/home/me/out.txt");
To write one specified character to an output stream, use the write method with one int parameter. The int parameter represents the character to write.
int aChar = (int)'X';
fileWriter.write(aChar);
To write a specific number of bytes from a specified char array starting at a given offset to an output stream, use the write method with a char[] parameter, an int offset parameter, and an int length parameter as shown in the following example:
fileWriter.write(buffer, 0, byteCount);
To close an output stream and release any system resources associated with the stream, use the close method, like this:
fileWriter.close();
To force any buffered data out of an output stream, use the flush method as follows:
fileWriter.flush();
Putting it all together
We can use what we have learned to read from one file and simultaneously write
to another, as demonstrated in Listing C.
Summary
The Java I/O facilities add a simple and standardized API for reading and
writing character and byte data from various data sources. Experience obtained
while working with Java streams for one type of data source can be carried over
to any other type of data source exposed by Java.
In our next article, we
will begin to explore the networking and remote communications frameworks of the
Java platform. We will extend our discussion of Java streams to these
environments and demonstrate how remote data sources can be opened, written to,
and read from in much the same manner as a local data source, such as a
file.