I/O Basics - Java

In fact, aside from print( ) and println( ), none of the I/O methods have been used significantly.

I/O
Basics

As you may have noticed while
reading the preceding 12 chapters, not much use has been made of I/O in the
example programs. In fact, aside from print(
) and println( ), none of the
I/O methods have been used significantly. The reason is simple: most real
applications of Java are not text-based, console programs. Rather, they are
either graphically oriented programs that rely on one of Java’s graphical user
interface (GUI) frameworks, such as Swing, the AWT, or JavaFX, for user
interaction, or they are Web applications. Although text-based, console
programs are excellent as teaching examples, they do not constitute an
important use for Java in the real world. Also, Java’s support for console I/O
is limited and somewhat awkward to use—even in simple example programs.
Text-based console I/O is just not that useful in real-world Java programming.

The preceding paragraph
notwithstanding, Java does provide strong, flexible support for I/O as it
relates to files and networks. Java’s I/O system is cohesive and consistent. In
fact, once you understand its fundamentals, the rest of the I/O system is easy
to master. A general overview of I/O is presented here. A detailed description
is found in Chapters 20 and 21.

Streams

Java programs perform I/O
through streams. A stream is an
abstraction that either produces or consumes information. A stream is linked to
a physical device by the Java I/O system. All streams behave in the same
manner, even if the actual physical devices to which they are linked differ.
Thus, the same I/O classes and methods can be applied to different types of
devices. This means that an input stream can abstract many different kinds of
input: from a disk file, a keyboard, or a network socket. Likewise, an output
stream may refer to the console, a disk file, or a network connection. Streams
are a clean way to deal with input/ output without having every part of your
code understand the difference between a keyboard and a network, for example.
Java implements streams within class hierarchies defined in the java.io package.

Byte
Streams and Character Streams

Java defines two types of
streams: byte and character. Byte streams
provide a convenient means for handling input and output of bytes. Byte streams
are used, for example, when reading or writing binary data. Character streams provide a convenient
means for handling input and output of characters. They use Unicode and,
therefore, can be internationalized. Also, in some cases, character streams are
more efficient than byte streams.

The original version of Java
(Java 1.0) did not include character streams and, thus, all I/O was
byte-oriented. Character streams were added by Java 1.1, and certain
byte-oriented classes and methods were deprecated. Although old code that
doesn’t use character streams is becoming increasingly rare, it may still be
encountered from time to time. As a general rule, old code should be updated to
take advantage of character streams where appropriate.

One other point: at the
lowest level, all I/O is still byte-oriented. The character-based streams
simply provide a convenient and efficient means for handling characters.

An overview of both
byte-oriented streams and character-oriented streams is presented in the
following sections.

The
Byte Stream Classes

Byte streams are defined by
using two class hierarchies. At the top are two abstract classes: InputStream and OutputStream. Each of these abstract classes has several concretesubclasses that handle the differences
among various devices, such as disk files, network connections, and even memory
buffers. The byte stream classes in java.io
are shown in Table 13-1. A few of these classes are discussed later in this
section. Others are described in Part II of this book. Remember, to use the
stream classes, you must import java.io.

The abstract classes InputStream and OutputStream define several key methods that the other stream
classes implement. Two of the most important are read( ) and write( ),
which, respectively, read and write bytes of data. Each has a form that is
abstract and must be overridden by derived stream classes.

The
Character Stream Classes

Character streams are defined
by using two class hierarchies. At the top are two abstract classes: Reader and Writer. These abstract classes handle Unicode character streams.
Java has several concrete subclasses of each of these. The character stream
classes in java.io are shown in
Table 13-2.

The abstract classes Reader and Writer define several key methods that the other stream classes
implement. Two of the most important methods are read( ) and write( ),
which read and write characters of data, respectively. Each has a form that is
abstract and must be overridden by derived stream classes.

The
Predefined Streams

As you know, all Java
programs automatically import the java.lang
package. This package defines a class called System, which encapsulates several aspects of the run-time
environment. For example, using some of its methods, you can obtain the current
time and the settings of various properties associated with the system. System also contains three predefined
stream variables: in, out, and err. These fields are declared as public, static, and final within System. This means that they can be used by any other part of your
program and withoutreference to a
specific System object.

System.out refers to the standard output stream. By default, this is the
console. System.in refers to
standard input, which is the keyboard by default. System.err refers to the standard error stream, which also is the
console by default. However, these streams may be redirected to any compatible
I/O device.

System.in is an object of type
InputStream; System.out and System.err are objectsof type PrintStream. These are byte streams, even though they are typically
used to read and write characters from and to the console. As you will see, you
can wrap these within character-based streams, if desired.

The preceding chapters have
been using System.out in their
examples. You can use System.err in
much the same way. As explained in the next section, use of System.in is alittle
more complicated.