Wednesday, June 27, 2007

Chapter 15 - The java.io Package

Chapter 15: The java.io Package

Objectives

This chapter helps you to prepare for the exam by covering the following objectives:

Know how the java.io package supports stream-based input and output.

.
A general knowledge of how Java supports I/O operations is required to develop programs
that are able to save and reuse their results.
Know how the java.io input and output class hierarchy is structured.

.. The java.io package supports a large number of classes and interfaces. Familiarity with
these classes and interfaces is required to answer some certification exam questions.
Know how the File class is used to access the directories and files of the local system.

.
The File class enables programs to access the local file system. For this reason, it is an
important class for many I/O operations. The certification exam contains questions that
require familiarity with this class.
Know how I/O filters are used.

.
The I/O filter classes combine the capabilities of different input or output streams. This
enables you to incorporate features, such as buffering, in your programs. I/O filtering is a
topic for the certification exam.
Know how character I/O is supported by the Reader and Writer classes.

.
The Reader and Writer classes support character-based I/O using different character
encodings. These capabilities are required to develop programs that support international
character sets.
- 257



Study Strategies

As you read through this chapter, you should concentrate on the following key items:

.
How I/O is accomplished using input stream, output stream, Reader and Writer classes
.
How the classes of the java.io package are structured
.. How the File object is used to access the local file system
.
How I/O filters are used
.
How international text is supported
Chapter Introduction

The capability to perform input and output is key to saving and reusing a program's results. Because
input and output are fundamental to programming, you may see a few exam questions related to the
java.io package. In this chapter, you'll learn to use Java streams to perform sophisticated input and
output, using standard I/O, memory buffers, and files. You'll explore the input and output class hierarchy
and learn to use stream filters to simplify I/O processing. You'll also learn how to perform random-
access I/O and access character encodings. By studying the class descriptions of this chapter and
working the programming examples, you should be able to do well on related exam questions.

Streams

Java input and output are based on the use of streams, which are sequences of bytes or characters that
travel from a source to a destination over a communication path. If your program is writing to a stream,
that program is the stream's source. If your program is reading from a stream, it is the stream's
destination. The communication path is dependent on the type of I/Os being performed. It can consist of
memory-to-memory transfers, a file system, a network, and other forms of I/O.

Streams are not complicated. They are powerful because they abstract the details of the communication
path from input and output operations. This enables all I/Os to be performed using a common set of
methods. These methods can be tailored and extended to provide higher-level, custom I/O capabilities.
Java defines two major classes of byte streams: InputStream and OutputStream. These streams
are subclassed to provide a variety of I/O capabilities. Java 1.1 introduced the Reader and Writer
classes to provide the foundation for 16-bit Unicode character-oriented I/O. These classes support
internationalization of Java I/O, allowing text to be stored using international character encodings.

The Java.Io Class Hierarchy

Figure 15.1 identifies the java.io class hierarchy. As described in the previous section, the
InputStream, OutputStream, Reader, and Writer classes are the major components of this
hierarchy. Other high-level classes include the File, FileDescriptor, RandomAccessFile,
ObjectStreamClass, and StreamTokenizer classes.
The InputStream and OutputStream classes have complementary subclasses. For example, both
have subclasses for performing I/O via memory buffers, files, and pipes. The InputStream subclasses
perform the input, and the OutputStream classes perform the output.
The InputStream class has several direct subclasses. The ByteArrayInputStream class is used
to convert an array into an input stream. The StringBufferInputStream class uses a
StringBuffer as an input stream. The FileInputStream class enables files to be used as input
streams. The ObjectInputStream class is used to read primitive types and objects that have been
previously written to a stream. The PipedInputStream class allows a pipe to be constructed between
two threads and supports input through the pipe. It is used in conjunction with the
PipedOutputStream class. The SequenceInputStream class enables two or more streams to be
concatenated into a single stream. The FilterInputStream class is an abstract class from which
other input-filtering classes are constructed.
Filters are objects that read from one stream and write to another, usually altering the data in some way
as they pass it from one stream to another. Filters can be used to buffer data, read and write objects,
keep track of line numbers, and perform other operations on the data they move. Filters can be
combined, with one filter using the output of another as its input. You can create custom filters by
combining existing filters.
FilterInputStream has a number of filtering subclasses. The BufferedInputStream class
maintains a buffer of the input data that it receives. This eliminates the need to read from the stream's

- 258



Figure 15.1: The classes of the java.io hierarchy.
The OutputStream class hierarchy consists of five direct subclasses. The
ByteArrayOutputStream, FileOutputStream, ObjectOutputStream, and
PipedOutputStream classes are the output complements to the ByteArrayInputStream,
FileInputStream, ObjectInputStream, and PipedInputStream classes. The
FilterOutputStream class provides subclasses that complement the FilterInputStreamclasses.
source every time an input byte is needed. The DataInputStream class implements the DataInput
interface, a set of methods that enable String objects and primitive data types to be read from a
stream. The LineNumberInputStream is used to keep track of input line numbers. The
PushbackInputStream provides the capability to push data back onto the stream that it is read from
so that it can be read again.

Note
Other Stream Classes Other Java API packages, such as java.util.zipand java.util.jar, contain classes and interfaces that

extend those of
java.io. These packages define input and output stream classes that can be
used to support file and stream compression.

The BufferedOutputStream class is the output analog to the BufferedInputStream class. It
buffers output so that output bytes can be written to devices in larger groups. The DataOutputStreamclass implements the

DataOutput interface. This interface complements the DataInput interface. It
provides methods that write String objects and primitive data types to streams so that they can be
read by the DataInput interface methods. The PrintStream class provides the familiar print()
and println() methods used to display output to the console window. PrintStream provides a
number of overloaded methods that simplify data output.
The Reader class is similar to the InputStream class because it is the root of an input class
hierarchy. Reader supports 16-bit Unicode character input, whereas InputStream supports 8-bit byte
input. The Reader class has six direct subclasses.

.
The BufferedReader class supports buffered character input. Its LineNumberReader
subclass supports buffered input and keeps track of line numbers.
- 259



.
The CharArrayReader class provides the capability to read a character input stream from
a character buffer.
.
The FilterReader class is an abstract class that provides the basis for filtering character
input streams. Its PushbackReader subclass provides a filter that allows characters to be
pushed back onto the input stream.
.
The InputStreamReader class is used to convert byte input streams to character input
streams. Its FileReader subclass is used to read character files.
.
The PipedReader class is used to read characters from a pipe.
.. The StringReader class is used to read characters from a String.
The Writer class is the output analog of the Reader class. It supports 16-bit Unicode character
output. It has seven direct subclasses:
.
The BufferedWriter class supports buffered character output.
.
The CharArrayWriter class supports output to a character array.
.
The FilterWriter class is an abstract class that supports character output filtering.
.
The OutputStreamWriter class enables a character stream to be converted to a byte
stream. Its FileWriter subclass is used to perform character output to files.
.
The PipedWriter class supports character output to pipes.
.
The PrintWriter class supports platform-independent character printing.
.. The StringWriter class supports character output to String objects.
The File class is used to access the files and directories of the local file system. The
FileDescriptor class is an encapsulation of the information used by the host system to track files
that are being accessed. The RandomAccessFile class provides the capabilities needed to directly
access data contained in a file. The ObjectStreamClass class is used to describe classes whose
objects can be written (serialized) to a stream. The StreamTokenizer class is used to create parsers
that operate on stream data.
New classes introduced with Java 2 include the ObjectInputStream.GetField,
ObjectOutputStream.PutField, and ObjectStreamField classes, which support object stream
I/O. The FilePermission and SerializablePermission classes support security access
controls.
Note
Serialization The process of converting objects to a format that is suitable for
stream input and output is referred to as serialization. Deserialization is the
process of converting a serialized object back to an object instance. In order for
an object to be serialized, it must implement the java.io.Serializableinterface.

The Java.Io Interfaces

The java.io package declares ten interfaces. The DataInput and DataOutput interfaces provide
methods that support machine-independent I/O. The ObjectInput and ObjectOutput interfaces
extend DataInput and DataOutput to work with objects. The ObjectInputValidation interface
supports the validation of objects that are read from a stream. The Serializable and
Externalizable interfaces support the serialized writing of objects to streams. The
FilenameFilter and FileFilter interfaces are used to select filenames from a list. The
ObjectStreamConstants interface defines constants that serialize objects to and from streams.

Note
Other Input/Output Classes Other packages, such as java.util.zip,

provide classes that extend the java.io class hierarchy shown in Figure 15.1.

The Inputstream Class

The InputStream class is an abstract class that lays the foundation for the Java byte-input class
hierarchy. As such, it provides methods that are inherited by all InputStream classes.

The read() Method

The read() method is the most important method of the InputStream class hierarchy. It reads a byte
of data from an input stream and blocks if no data is available. When a method blocks, it causes the
thread in which it is executing to wait until data becomes available. This is not a problem in
multithreaded programs. The read() method takes on several overloaded forms. It can read a single
byte or an array of bytes, depending upon what form is used. If it reads a single byte then it returns the
byte that is read. If it reads an array of bytes it returns the number of bytes read. In both cases it returns
-1 if an end of file is encountered with no bytes read.
The read() method is overridden and overloaded by subclasses to provide custom-read capabilities.

- 260



The available() Method

The available() method returns the number of bytes that are available to be read without blocking. It
is used to peek into the input stream to see how much data is available. However, depending on the
input stream, it might not be accurate or useful. Some input streams on some operating systems may
always report 0 available bytes when data is available from a stream. In general, it is not a good idea to
blindly rely on this method to perform input processing.

The close() Method

The close() method closes an input stream and releases resources associated with the stream. It is
always a good idea to close a stream to ensure that the stream processing is correctly terminated.

Markable Streams

Java supports markable streams. These are streams that provide the capability to mark a position in the
stream and then later reset the stream so that it can be reread from the marked position. If a stream can
be marked, it must contain some memory to keep track of the data between the mark and the current
position of the stream. When this buffering capability is exceeded, the mark becomes invalidated.
The markSupported() method returns a boolean value that identifies whether a stream supports
mark and reset capabilities. The mark() method marks a position in the stream. It takes an integer
parameter that identifies the number of bytes that can be read before the mark becomes invalid. This is
used to set the buffering capacity of the stream. The reset() method simply repositions the stream to
its last marked position.

The skip() Method

The skip() method skips over a specified number of input bytes. It takes a long value as a
parameter. You can use the skip() method to move to a specific position within an input stream.

The Outputstream Class

The OutputStream class is an abstract class that lays the foundation for the byte output stream
hierarchy. It provides a set of methods that are the output analog to the InputStream methods.

The write() Method

The write() method enables bytes to be written to the output stream. It provides three overloaded
forms to write a single byte, an array of bytes, or a segment of an array. The write() method, like the
read() method, may block when it tries to write to a stream. The blocking causes the thread executing
the write() method to wait until the write operation has been completed.

Note Overloading The OutputStream class defines three overloaded forms for the

write() method. These forms allow you to write an integer, an array of bytes, or

a subarray of bytes to an OutputStream object. You will often see several

overloaded forms for methods that perform the same operation using different

types of data.

The flush() Method

The flush() method causes any buffered data to be immediately written to the output stream. Some
subclasses of OutputStream support buffering and override this method to clean out their buffers and
to write all buffered data to the output stream. They must override the OutputStreamflush()
method because, by default, it does not perform any operations and is used as a placeholder.

The close() Method

It is generally more important to close() output streams than input streams, so that any data written to
the stream is stored before the stream is deallocated and lost. The close() method of
OutputStream is used in the same manner as that of InputStream.

Byte Array I/O

Java supports byte array input and output via the ByteArrayInputStream and
ByteArrayOutputStream classes. These classes use memory buffers (arrays) as the source and
destination of the input and output streams. The contents of the memory buffers are written and read
from the streams. The StringBufferInputStream class is similar to the ByteArrayInput class,
but was deprecated in JDK 1.1. The StringReader class is now the preferred class for String-based
input.
The CharArrayReader, CharArrayWriter, StringReader, and StringWriter classes support
character-based I/O in a manner similar to the ByteArrayInputStream,

- 261



ByteArrayOutputStream, and StringBufferInputStream classes. They are covered later in this
chapter.

The ByteArrayInputStreamClass

The ByteArrayInputStream class creates an input stream from a memory buffer. The buffer is an
array of bytes. It provides two constructors that use a byte array argument to create the input stream.
The class does not support any new methods, but overrides the read(), skip(), available(), and
reset() methods of InputStream.
The read() and skip() methods are implemented as specified for InputStream. The
available() method is reliable and can be used to check on the number of available bytes in the
buffer. The reset() method resets the stream to a marked position.

The ByteArrayOutputStream Class

The ByteArrayOutputStream class is a little more sophisticated than its input complement. It
creates an output stream on a byte array, but provides additional capabilities to enable the output array
to grow to accommodate new data that is written to it. It also provides the toByteArray() and
toString() methods for converting the stream data to a byte array or String object.
ByteArrayOutputStream provides some additional methods not declared for OutputStream. The
reset() method resets the output buffer to allow writing to restart at the beginning of the buffer. The
size() method returns the current number of bytes that have been written to the buffer. The
writeTo() method takes an object of class OutputStream as an argument and writes the contents
of the output buffer to the specified output stream. The write() methods override those of
OutputStream to support array output.

File I/O

Java supports stream-based file input and output through the File, FileDescriptor,
FileInputStream, and FileOutputStream classes. It supports direct or random access I/O using
the File, FileDescriptor, and RandomAccessFile classes. Random access I/O is covered later
in this chapter. The FileReader and FileWriter classes support Unicode-based file I/O. These
classes are also covered later in this chapter.
The File class provides access to file and directory objects and supports a number of operations on
files and directories. The FileDescriptor class encapsulates the information used by the host
system to track files that are being accessed. The FileInputStream and FileOutputStreamclasses provide the capability to read

and write to file streams.

The FileClass

The File class is used to access file and directory objects. It uses the file-naming conventions of the
host operating system. The File class encapsulates these conventions using the File class
constants.
File provides constructors for creating files and directories. These constructors take absolute and
relative file paths, filenames, and directory names.
The File class provides numerous access methods that can be used to perform all common file and
directory operations. File methods enable files to be created, deleted, and renamed. They provide
access to a file's pathname and determine whether a File object is a file or directory. These methods
also check read and write access permissions.

Directory-oriented methods enable directories to be created, deleted, renamed, and listed. Directory
methods also allow directory trees to be traversed by providing access to the parent and sibling
directories.
The FileApp program, shown in Listing 15.1, shows how the File class can be used to traverse a
system's directory structure. Figure 15.2 shows the program's opening display. It lists directories in the
top of the window and files in the bottom. Double-click a directory name, and that directory's contents
are listed as shown in Figure 15.3.

Note Listing the Current Directory You can list the contents of the current directory

by creating a File object using new File(".") and then invoking its

listFiles() method. However, the File class does not provide any method to

change the current directory.

- 262



Figure 15.2: The FileApp program's opening display.


Figure 15.3: Listing the contents of a directory.
You should note the following points about how FileApp uses the File class:

.
The listRoots() method is used to access an array of File objects that represent your
system's root directories. The root directories are represented by ---roots---in the
program.
.
The getAbsolutePath() method returns the full pathname of a file or directory.
.
The getParent() method returns the name of a directory's parent directory or null if it
is a system root.
.
The listFiles() method returns an array of File objects corresponding to all
directories and files in a directory.
.
The isDirectory() and isFile() methods identify a File object as a directory or a
file.
.
The getName() method returns the name of a file or directory.
FileappListing 15.1: The Program

import java.awt.*;
import java.awt.event.*;
import java.io.*;

public class FileApp extends Frame {

- 263



List list = new List(5)
;
TextArea textArea = new TextArea(10,80)
;
File[] roots = File.listRoots()
;
public static void main(String[] args)
{


FileApp app = new FileApp()
;
}
public FileApp()
{


super("FileApp")
;
setup()
;
addWindowListener(new WindowEventHandler())
;
pack()
;
setSize(450,450)
;
show()
;


}


public void setup()
{
setFont(new Font("Courier",Font.BOLD,12))
;
setLayout(new GridLayout(2,1))
;
for(int i=0;i

list.add(roots[i].getAbsolutePath())
;
list.addActionListener(new ListHandler())
;
add(list)
;
add(textArea)
;


}


void updateWindow(File file)
{
File[] contents = file.listFiles()
;
list.removeAll()
;
String parent = file.getParent()
;
if(parent == null) list.add("---roots---")
;
else list.add(parent)
;
String text = "Files:\n"
;
for(int i=0;i{


- 264



if(contents[i].isDirectory()
)
list.add(contents[i].getAbsolutePath())
;
if(contents[i].isFile()
)


text += "\n" + contents[i].getName()
;
}
textArea.setText(text)
;


}
class ListHandler implements ActionListener
{


public void actionPerformed(ActionEvent e)
{
String item = (String) e.getActionCommand()
;
if(item.equals("---roots---"))
{


list.removeAll()
;
for(int i=0;ilist.add(roots[i].getAbsolutePath())
;


textArea.setText("")
;
}else updateWindow(new File(item))
;
validate()
;


}
}
class WindowEventHandler extends WindowAdapter{

public void windowClosing(WindowEvent e) {
System.exit(0);
}
}

}
The FileDescriptorClass

The FileDescriptor class provides access to the file descriptors maintained by operating systems
when files and directories are being accessed. This class is opaque in that it does not provide visibility
into the specific information maintained by the operating system.

The FileInputStream Class

The FileInputStream class enables input to be read from a file in the form of a stream. Objects of
class FileInputStream are created using a filename string or a File or FileDescriptor object as
an argument. FileInputStream overrides the methods of the InputStream class and provides two

- 265



new methods, finalize() and getFD(). The finalize() method closes a stream when it is
processed by the Java garbage collector. The getFD() method is used to obtain access to the
FileDescriptor associated with the input stream.

The FileOutputStreamClass

The FileOutputStream class enables output to be written to a file stream. Objects of class
FileOutputStream are created in the same way as objects of class FileInputStream, using a
filename string, File object, or FileDescriptor object as an argument. FileOutputStreamoverrides the methods of the

OutputStream class and supports the finalize() and getFD()
methods described for the FileInputStream class.

The FileIOApp Program

The program in Listing 15.2 illustrates the use of the FileInputStream, FileOutputStream, and
File classes. It writes a string to an output file and then reads the file to verify that the output was

written correctly. The file used for the I/O is then deleted.
Listing 15.2: The Source Code of the Fileioapp Program
import java.io.*;

public class FileIOApp {

public static void main(String args[]) throws IOException {
// Create output file test.txt
FileOutputStream outStream = new FileOutputStream("test.txt");
String s = "This is a test.";
for(int i=0;i
outStream.write(s.charAt(i));
outStream.close();
// Open test.txt for input
FileInputStream inStream = new FileInputStream("test.txt");
int inBytes = inStream.available();
System.out.println("inStream has "+inBytes+" available bytes");
byte inBuf[] = new byte[inBytes];
int bytesRead = inStream.read(inBuf,0,inBytes);
System.out.println(bytesRead+" bytes were read");
System.out.println("They are: "+new String(inBuf));
inStream.close();
File f = new File("test.txt");
f.delete();

}

- 266



}



The FileOutputStream constructor creates an output stream on the file test.txt. The file is
automatically created in the current working directory. It then writes the string "This is a test." to
the output file stream. The output stream is closed to make sure that all the data is written to the file.
The file is then reopened as an input file by creating an object of class FileInputStream. The
program determines the number of available bytes in the file and reads these bytes into a byte array.
The number of bytes read is displayed along with the characters corresponding to those bytes.

The program's output follows:

inStream has 15 available bytes

15 bytes were read

They are: This is a test.

The Sequenceinputstream Class

The SequenceInputStream class is used to combine two or more input streams into a single input
stream. The input streams are concatenated, which allows the individual streams to be treated as a
single, logical stream. The SequenceInputStream class does not introduce any new access
methods. Its power is derived from the two constructors that it provides. One constructor takes two
InputStream objects as arguments. The other takes an Enumeration of InputStream objects.

Filtered I/O

The filtered input and output stream classes provide the capability to filter I/O in a number of useful
ways. I/O filters adapt streams to specific program needs. These filters sit between an input stream and
an output stream and perform special processing on the bytes they transfer from input to output. You
can combine filters to perform a sequence of filtering operations, where one filter acts on the output of
another, as shown in Figure 15.4.


Figure 15.4: Combining filters.
The FilterInputStream Class
The FilterInputStream class is an abstract class that is the parent of all filtered input stream
classes. The FilterInputStream class provides the basic capability to create one stream from
another. It allows one stream to be read and provided as output as another stream. This is
accomplished through the use of the in variable, which is used to maintain a separate object of class
InputStream. The design of the FilterInputStream class enables multiple chained filters to be
created using several layers of nesting. Each subsequent class accesses the output of the previous
class through the in variable. Because the in variable is an object of class InputStream, arbitrary
InputStream objects can be filtered.

The FilterOutputStream Class

The FilterOutputStream class is the complement to the FilterInputStream class. It is an
abstract class that is the parent of all filtered output stream classes. It is similar to the
FilterInputStream class because it maintains an object of class OutputStream as an out
variable. Data written to an object of FilterOutputStream can be modified as needed to perform
filtering operations and then forwarded to the outOutputStream object. Because out is declared to
be of class OutputStream, arbitrary output streams can be filtered. Multiple FilterOutputStreamobjects can be combined in a

manner that is analogous to FilterInputStream objects. The input of
subsequent FilterOutputStream objects is linked to the output of preceding objects.

Buffered I/O

Buffered input and output is used to temporarily cache data that is read from or written to a stream. This
enables programs to read and write small amounts of data without adversely affecting system
performance. When buffered input is performed, a large number of bytes are read at a single time and

- 267



stored in an input buffer. When a program reads from the input stream, the input bytes are read from the
input buffer. Several reads may be performed before the buffer needs to refilled. Input buffering is used
to speed up overall stream input processing.

Output buffering is performed in a manner similar to input buffering. When a program writes to a stream,
the output data is stored in an output buffer until the buffer becomes full or the output stream is flushed.
Only then is the buffered output actually forwarded to the output stream's destination.

Java implements buffered I/O as filters. The filters maintain and operate the buffer that sits between the
program and the source or destination of a buffered stream.

The BufferedInputStream Class

The BufferedInputStream class supports input buffering by automatically creating and maintaining
a buffer for a designated input stream. This enables programs to read data from the stream one byte at
a time without degrading system performance. Because the BufferedInputStream class is a filter, it
can be applied to arbitrary objects of class InputStream and combined with other input filters.
BufferedInputStream defines two constructors. One allows the size of an input buffer to be
specified, and the other does not. Both constructors take an object of class InputStream as an
argument. It is usually better to let BufferedInputStream select the best size for the input buffer
than to specify a size yourself, unless you have specific knowledge that one buffer size is better than
another.
BufferedInputStream overrides the access methods provided by InputStream and does not
introduce any new methods of its own.

The BufferedOutputStream Class

The BufferedOutputStream class performs output buffering in a manner that is analogous to
BufferedInputStream. It enables you to specify the size of the output buffer in a constructor. It also
provides for a default buffer size. It overrides the methods of the OutputStream class and does not
introduce any new methods of its own.

PushbackInputStream

PushbackInputStream is a filter that lets you push a byte that was previously read back onto the
input stream so that it can be reread. This type of filter is commonly used with parsers. When a
character indicating a new input token is read, it is pushed back onto the input stream until the current
input token is processed. It is then reread when processing of the next input token is initiated.
PushbackInputStream allows only a single byte to be pushed back. This is generally enough for
most applications.
The pushback character is stored in a variable named pushBack.
The unread() method is the only new method introduced by this class. It is used to push a specified
character back onto the input stream.

The LineNumberInputStream Class

The LineNumberInputStream class provides a handy capability for keeping track of input line
numbers. It is also a subclass of FilterInputStream. This class provides two new methods to
support line number processing. The setLineNumber() method is used to set the current line number
to a particular value. The getLineNumber() method is used to obtain the value of the current line
number.
Up until Java 1.1, the LineNumberInputStream class was the preferred class for tracking input line
numbers. In Java 1.1, significant support was added for internationalization. As a result, the
LineNumberInputStream class has been deprecated. The LineNumberReader class (covered later
in this chapter) is now the preferred class for tracking input line numbers.

Data I/O

The DataInputStream and DataOutputStream classes implement the DataInput and
DataOutput interfaces. These interfaces identify methods that enable primitive data types to be read
from and written to a stream. By implementing these interfaces, the DataInputStream and
DataOutputStream classes provide the basis for implementing portable input and output streams.

The DataInputStream Class

The DataInputStream class provides the capability to read String objects and primitive types from
an input stream. It implements the methods of the DataInput interface. These methods provide a full
range of input capabilities:

.
readBoolean()—Reads a boolean value
- 268



.
readByte()—Reads a byte as an 8-bit, signed value
.
readChar()—Reads a Unicode character
.
readDouble()—Reads a double value
.
readFloat()—Reads a float value
.
readFully()—Reads an array of bytes
.
readInt()—Reads an int value
.
readLine()—Reads a line of text (deprecated)
.
readLong()—Reads a long value
.
readShort()—Reads a short value
.
readUnsignedByte()—Reads a byte as an 8-bit, unsigned value
.
readUnsignedShort()—Reads an unsigned 16-bit value
.
readUTF()—Reads a string that is in the UTF-8 format
.
skipBytes()—Skips over a specified number of input bytes
Note that most, but not all, of these methods raise the EOFException when an end of file is
encountered. The readLine() method returns a null value to signify a read past the end of a file.
This method was deprecated in Java 1.1. The readLine() method of the BufferedReader class
should be used instead. BufferedReader provides better support for internationalization. Its
readLine() method corrects errors that exist in the readLine() method of DataInputStream.
Note
UTF-8 The UTF-8 character encoding is covered later in this chapter in the
section, "Character Sets and Codings."

The DataOutputStream Class

The DataOutputStream class provides an output complement to DataInputStream. It enables
String objects and primitive data types to be written to an output stream. It also keeps track of the
number of bytes written to the output stream. It is an output filter and can be combined with any output-
filtering streams.

The PrintStream Class

The PrintStream class should be no stranger to you. The System.out object that you have been
using for many of the console programs in this book is an instance of the PrintStream class. It is
used to write output to the Java console window.
PrintStream's power lies in the fact that it provides two methods, print() and println(), that are
overloaded to print any primitive data type or object. Objects are printed by first converting them to
strings using their toString() method, inherited from the Object class. To provide custom printing
for any class, all you have to do is override the toString() method for that class.
PrintStream provides the capability to automatically flush all output bytes in the stream when a new
line character is written to the stream. This feature can be enabled or disabled when the stream is
created.
Because PrintStream is a filter, it takes an instance of OutputStream as an argument to its
constructor. A second constructor adds the capability to use the autoflushing feature.
PrintStream introduces only one new method besides the extensively overloaded print() and
println() methods. The checkError() method is used to flush stream output and determine
whether an error occurred on the output stream. This capability is useful for printing output to devices,
such as printers, where error status is needed to notify the user of any changes to the device state.

Piped I/O

Piped I/O provides the capability for threads to communicate via streams. A thread sends data to
another thread by creating an object of PipedOutputStream that it connects to an object of
PipedInputStream. The output data written by one thread is read by another thread using the
PipedInputStream object.
The process of connecting piped input and output threads is symmetric. An object of class
PipedInputThread can also be connected to an existing object of class PipedOutputThread.

Java automatically performs synchronization with respect to piped input and output streams. The thread
that reads from an input pipe does not have to worry about any conflicts with tasks that are being written
to the corresponding output stream thread.
Both PipedInputStream and PipedOutputStream override the standard I/O methods of
InputStream and OutputStream. The only new method provided by these classes is the
connect() method. Both classes provide the capability to connect piped streams via their
constructors.

- 269



Object I/O

The ObjectOutputStream and ObjectInputStream classes enable objects and values of primitive
types to be written to and read from streams. These classes implement the ObjectOutput and
ObjectInput interfaces. Of the methods specified by ObjectOutput, the writeObject() method
is the most interesting; it writes objects that implement the Serializable interface to a stream. The
ObjectInput interface provides the readObject() method to read the objects written to a stream by
the writeObject() method.

When an object is stored in a serialized form, information is stored with the object that identifies the
Java class from which the contents of the object were saved and allows the object to be restored as a
new instance of that class. In addition, when an object is serialized, all of the non-transient and non-
static objects that are reachable from that object are also stored with that object.
The Serializable interfaces are used to identify objects that can be written to a stream. It does not
define any constants or methods.

The ObjectIOApp Program

The ObjectIOApp program, Listing 15.3, shows how the ObjectOutputStream and
ObjectInputStream classes can be used to write and read objects from streams.


ObjectioappListing 15.3: The Source Code of the Program

import java.io.*;
import java.util.*;

public class ObjectIOApp {
public static void main(String args[]) throws IOException,

ClassNotFoundException {
File file = new File("test.txt");
FileOutputStream outFile = new FileOutputStream(file);
ObjectOutputStream outStream = new ObjectOutputStream(outFile);
TestClass1 t1 = new TestClass1(true,9,'A',0.0001,"java");
TestClass2 t2 = new TestClass2();
String t3 = "This is a test.";
Date t4 = new Date();
// Write objects to stream
outStream.writeObject(t1);
outStream.writeObject(t2);
outStream.writeObject(t3);
outStream.writeObject(t4);
outStream.close();
outFile.close();

- 270



FileInputStream inFile = new FileInputStream(file);

ObjectInputStream inStream = new ObjectInputStream(inFile);

// Read objects from stream and display them

System.out.println(inStream.readObject());

System.out.println(inStream.readObject());

System.out.println(inStream.readObject());

System.out.println(inStream.readObject());

inStream.close();

inFile.close();

file.delete();

}
}

class TestClass1 implements Serializable {

boolean b;

int i;

char c;

double d;

String s;

TestClass1(boolean b,int i,char c,double d,String s){

this.b = b;

this.i = i;

this.c = c;

this.d = d;

this.s = s;

}

public String toString(){

String r = String.valueOf(b)+" ";

r += String.valueOf(i)+" ";

r += String.valueOf(c)+" ";

r += String.valueOf(d)+" ";

- 271



r += String.valueOf(s);
return r;
}
}

class TestClass2 implements Serializable {
int i;
TestClass1 tc1;
TestClass1 tc2;
TestClass2(){

i=0;
tc1 = new TestClass1(true,2,'j',1.234,"Java")
;
tc2 = new TestClass1(false,7,'J',2.468,"JAVA")
;


}


public String toString()
{
String r = String.valueOf(i)+" "
;
r += tc1.toString()+" "
;
r += tc2.toString()
;
return r;


}


}
ObjectIOApp creates a File object that is used to perform I/O to the test.txt file. The File object
is used to create an object of class FileOutputStream. This object is then used to create an object of
class ObjectOutputStream, which is assigned to the outStream variable.
Four objects are created and assigned to the t1 through t4 variables. An object of class TestClass1
is assigned to the t1 variable, and an object of class TestClass2 is assigned to the t2 variable. The
TestClass1 and TestClass2 classes are declared at the end of Listing 15.3. A String object is
assigned to t3, and a Date object is assigned to t4.
The objects referenced by the t1 through t4 variables are written to outStream using the
writeObject() method. The stream and file are then closed. The test.txt file is reopened as a
FileInputStream object, which is then converted to an ObjectInputStream object and assigned
to the inStream variable. Four objects are read from inStream, using the readObject() method;
then they are written to standard output. The program's output is as follows:

true 9 A 1.0E-4 java
0 true 2 j 1.234 Java false 7 J 2.468 JAVA
This is a test.

- 272



Sun Feb 07 02:48:43 PST 1999
Note that you'll receive a different date value from this one. TestClass1 and TestClass2 are dummy
test classes that are used to make the example work. Their toString() methods are automatically
invoked by the println() method to convert objects to string values for printing.

The Reader and Writer Classes

The Reader and Writer classes are abstract classes, at the top of a class hierarchy, that support the
reading and writing of Unicode character streams. These classes were introduced with Java 1.1.

The Reader Class

The Reader class supports the standard read(), reset(), skip(), mark(), markSupported()
,
and close() methods. In addition to these, the ready() method returns a boolean value that
indicates whether the next read operation will succeed without blocking.
The direct subclasses of the Reader class are BufferedReader, CharArrayReader,
FilterReader, InputStreamReader, PipedReader, and StringReader.


The Writer Class

The Writer class is the output complement to the Reader class. It declares the write(), flush(),
and close() methods. Its direct subclasses are BufferedWriter, CharArrayWriter,
FilterWriter, OutputStreamWriter, PipedWriter, StringWriter, and PrintWriter. Each
of these subclasses, except PrintWriter, is an output complement to a Reader subclass.

Character Array and String I/O

The CharArrayReader and CharArrayWriter classes are similar to the ByteArrayInputStreamand ByteArrayOutputStream classes in

that they support I/O from memory buffers. The difference
between these classes is that CharArrayReader and CharArrayWriter support 16-bit character
I/O, and ByteArrayInputStream and ByteArrayOutputStream support 8-bit byte array I/O.
The CharArrayReader class does not add any new methods to those provided by Reader. The
CharArrayWriter class adds the following methods to those provided by Writer:

.
reset()—Resets the buffer so that it can be read
.
size()—Returns the current size of the buffer
.
toCharArray()—Returns a character array copy of the output buffer
.
toString()—Copies and converts the output buffer to a String object
.
writeTo()—Writes the buffer to another output stream (Writer object)
These methods are similar to those provided by the ByteArrayOutputStream class.
The StringReader class provides the capability to read character input from a string. Like
CharArrayReader, it does not add any additional methods to those provided by Reader. The
StringWriter class is used to write character output to a StringBuffer object. It adds the
getBuffer() and toString() methods. The getBuffer() method returns the StringBufferobject corresponding to the output buffer.

The toString() method returns a String copy of the
output buffer.
The CharArrayIOAppand StringIOApp Programs

The CharArrayIOApp program (see Listing 15.4) writes the string "This is a test." one
character at a time to a CharArrayWriter object. It then converts the output buffer to a
CharArrayReader object. Each character of the input buffer is read and appended to a
StringBuffer object. The StringBuffer object is then converted to a String object. The number
of characters read and the String object are then displayed. The program output follows:

outstream: This is a test.

size: 15

15 characters were read

They are: This is a test.
The StringIOApp program (see Listing 15.5) is similar to CharArrayIOApp. It writes output to a
StringBuffer instead of a character array. It produces the same output as CharArrayIOApp.
Listing 15.4: The Source Code of the CharArrayIOApp Program
import java.io.*;

- 273



public class CharArrayIOApp {

public static void main(String args[]) throws IOException {
CharArrayWriter outStream = new CharArrayWriter();
String s = "This is a test.";
for(int i=0;i
outStream.write(s.charAt(i));
System.out.println("outstream: "+outStream);
System.out.println("size: "+outStream.size());
CharArrayReader inStream;
inStream = new CharArrayReader(outStream.toCharArray());
int ch=0;
StringBuffer sb = new StringBuffer("");
while((ch = inStream.read()) != -1)

sb.append((char) ch)
;
s = sb.toString()
;
System.out.println(s.length()+" characters were read")
;
System.out.println("They are: "+s)
;


}

}
Listing 15.5: The Source Code of the Stringioapp Program


import java.io.*;

public class StringIOApp {

public static void main(String args[]) throws IOException {
StringWriter outStream = new StringWriter();
String s = "This is a test.";
for(int i=0;i
- 274



outStream.write(s.charAt(i))
;
System.out.println("outstream: "+outStream)
;
System.out.println("size: "+outStream.toString().length())
;
StringReader inStream;
inStream = new StringReader(outStream.toString())
;
int ch=0;
StringBuffer sb = new StringBuffer("")
;
while((ch = inStream.read()) != -1)


sb.append((char) ch)
;
s = sb.toString()
;
System.out.println(s.length()+" characters were read")
;
System.out.println("They are: "+s)
;


}
}

Character Sets and Codings

Most of us are familiar with the ASCII character set. This 7-bit character set represents the upper and
lower case letters a-z, digits 0-9, control characters, and special characters. Although this character set
is sufficient for most English-language programs, it is not sufficient for programs in other languages,
such as Spanish and German, which require special accent marks, and Japanese, which requires a
whole new character set.

Unlike most other programming languages, Java provides comprehensive support for the Unicode 2.0
character set. Unicode is a 16-bit character set, meaning that it is capable of representing 65,536
characters. This is a large character set and can be used to represent the characters used by many (but
not all) of the world's popular languages. The 128 characters of the ASCII character set are the first 128
characters of Unicode.

Note ASCII ASCII stands for American Standard Code for Information Interchange.

Note Unicode More information about the Unicode character set can be found at

http://www.unicode.org.
Unicode Variants

Some languages, such as varieties of Japanese, Chinese, and Korean, require more than 16 bits for full
representation. These languages use a Unicode variant known as UTF-16. UTF stands for UCS
Transformation Format and UCS stands for Universal Character Set. That's quite an acronym! In
addition to UTF-16, there is a UTF-8. UTF-8 is a multi-byte representation of Unicode. It enables ASCII
characters to be represented using one byte (instead of two) and other Unicode characters using two or
three bytes. If your use of Unicode is minimal, then UTF-8 can help to minimize your storage or

transmission requirements.
- 275



Unicode characters are written in Java using Unicode escape character sequences. These sequences
are of the form \uxxxx, where the four x's are replaced with hexadecimal digits. Each of the four
hexadecimal digits represents four bits of a 16-bit Unicode character.
To display Unicode characters other than ASCII, you need a Unicode font. In the absence of such a
font, Java displays Unicode characters using the \uxxxx notation. The Bitstream Cyberbit font is an
example of a font that supports Unicode. It can be downloaded from the Bitstream Web site at
http://www.bitstream.com/cyberbit/ftpcyber.htm.
Java represents char values as 16-bit Unicode characters and String objects are as collections of
16-bit Unicode characters. However, when Unicode data is written to or read from a stream, the
stream's data must be associated with a character encoding. A character encoding is a mapping
between the way data is represented internally (as Unicode) and externally as binary stream data.
Every platform has a default character encoding, and this default encoding works in most cases. For
example, the Cp1252 character encoding is used with English-language Windows platforms, and
Cp1251 is used with Cyrillic-language platforms. On Solaris and other systems, the English-language
encoding may be ISO8859_1.
In most cases, the default character coding is sufficient. However, in some cases, you may want to
change the character encoding of a stream in order to communicate with an application that uses a
different character encoding. The InputStreamReader and OutputStreamWriter classes, that are
introduced in the next section, enable the default character coding to be changed to an alternate
character coding.

The Inputstreamreader and Outputstreamwriter Classes

The InputStreamReader and OutputStreamWriter classes are used to convert between byte
streams and character streams. The InputStreamReader class converts an object of an
InputStream subclass into a character-oriented stream. The OutputStreamWriter class converts a
character output stream to a byte output stream.

The InputStreamReader Class

The InputStreamReader() constructor takes an InputStream object as a parameter and creates
an InputStreamReader object. This provides a bridge between byte-oriented input streams and
character-oriented input streams. A second InputStreamReader constructor also takes a Stringparameter that identifies the

character encoding to be used in byte-to-character conversion. The
getEncoding() method may be used to retrieve the encoding that is in effect. The ready() method
is used to determine whether a character can be read without blocking.

The InputConversionApp Program

The InputConversionApp program, shown in Listing 15.6, converts the standard input stream
(System.in) from a byte stream to a character stream. The input characters are echoed to standard
output. The program also prints out the encoding that is in effect on your system. The following is an
example of the output generated when the program is run on my computer:

Encoding: Cp1252

>This is a test.

This is a test.

>
The Cp1252 encoding is the MS Windows Latin-1 character encoding. It is used with English and
Western European languages.


InputconversionappListing 15.6: The Source Code of the Program

import java.io.*;

public class InputConversionApp {
public static void main(String args[]) throws IOException {

- 276



InputStreamReader in = new InputStreamReader(System.in)
;
BufferedReader inStream = new BufferedReader(in)
;
// Get the encoding that is in use
System.out.println("Encoding: "+in.getEncoding())
;
String inputLine;
do
{


System.out.print(">")
;
System.out.flush()
;
inputLine=inStream.readLine()
;
System.out.println(inputLine)
;


} while (inputLine.length() != 0);
}

}
The OutputStreamWriter Class

The OutputStreamWriter class enables a character stream to be converted to a byte stream. Its
constructor takes the name of an object of an OutputStream subclass as a parameter. The characters
written to an OutputStreamWriter object are translated and written to the OutputStream object
specified in the OutputStreamWriter object's constructor. The translation is performed according to
the encoding specified in the System property file.encoding. A different encoding scheme may be
specified by supplying the name of the encoding scheme in the OutputStreamWriter constructor.
The getEncoding() method may be used to retrieve the current character encoding that is in effect.

The Filereader and Filewriter Classes

The FileReader and FileWriter classes are subclasses of InputStreamReader and
OutputStreamWriter that are used to perform character-based file I/O. These classes do not provide
any additional access methods. However, their constructors provide the capability to create input and
output character streams using Stringobjects that represent filenames, File objects, and
FileDescriptor objects.

The CharFileIOApp Program

Listing 15.7 demonstrates the use of the FileReader and FileWriter classes. It converts the
FileIOApp program that was introduced earlier in the chapter (Listing 15.2) to character-oriented I/O
and produces the following output:

15 characters were read


They are: This is a test.
The main difference between CharFileIOApp and FileIOApp is that FileReader and
FileWriter classes are used instead of the FileInputStream and FileOutputStream classes.
The other difference is the use of a StringBuffer object (instead of a byte array) to capture the
characters read from the input file stream.


CharFileIOAppListing 15.7: The Source Code of the Program

import java.io.*;

- 277



public class CharFileIOApp {
public static void main(String args[]) throws IOException {
FileWriter outStream = new FileWriter("test.txt");
String s = "This is a test.";
for(int i=0;ioutStream.write(s.charAt(i));
outStream.close();
FileReader inStream = new FileReader("test.txt");
StringBuffer sb = new StringBuffer("");
int ch=0;
while((ch = inStream.read()) != -1)
sb.append((char) ch);
s = sb.toString();
System.out.println(s.length()+" characters were read");
System.out.println("They are: "+s);
inStream.close();
File f = new File("test.txt");
f.delete();
}

}

Buffered Character I/O

Buffered character I/O is supported by the BufferedReader and BufferedWriter classes. These
classes are character-based analogs to the BufferedInputStream and BufferedOutputStreamclasses. In Java 1.1, the readLine()

method of the BuffereddReader class replaced the
readLine() method of the DataInputStream class for reading lines of text from the console, a file,
or other character-oriented input streams.
The BufferedWriter class provides the capability to write buffered data to character-based output
streams. It adds the newLine() method to the methods that it inherits (and overrides) from the Writer
class. The newLine() method enables new line characters to be written in a system-independent
manner. Using this method is preferable to simply writing an \n character to the output stream. The
line.separator system property defines the system-specific new line character.

The LineNumberReaderClass

The LineNumberReader class is a subclass of the BufferedReader class that is used to associate
line numbers with each line of text that is read from a stream. Lines are terminated by a new line
character (\n), a carriage return (\r), or a carriage return-new line combination (\r\n).
In addition to the methods that it inherits from BufferedReader, the LineNumberReader class
declares the getLineNumber() and setLineNumber() methods. The getLineNumber() method

- 278



returns the current line number. The setLineNumber() method sets the current line number to an
integer value.

Filtered Character I/O

The FilterReader and FilterWriter classes are character-oriented analogs of the
FilterInputStream and FilterOutputStream classes. The FilterReader class uses the in
variable for input filtering and FilterWriter class uses the out variable for output filtering. Consult
the section "Filtered I/O" earlier in this chapter for a description of I/O filtering.

The PushbackReaderClass

The PushbackReader class is a subclass of FilterReader that provides the capability to push a
character that was previously read back onto the input stream so that it can be read again. It is the
character-oriented analog of the PushbackInputStream class that you studied earlier in the chapter.

The Pipedreader and Pipedwriter Classes

The PipedReader and PipedWriter classes support character-oriented piped I/O in the same way
that PipedInputStream and PipedOutputStream support byte-oriented piped I/O. Consult the
section "Piped I/O," earlier in this chapter, for a description of piped input and output.

The Printwriter Class

The PrintWriter class is the character-oriented replacement for the PrintStream class.
PrintWriter is now the preferred class for character printing. The PrintWriter class improves
PrintStream by using a platform-dependent line separator to print lines instead of the new line (\n)
character. The System line.separator property identifies the system unique line separator.
PrintWriter also provides better support for Unicode characters than PrintStream. The
checkError() method is used to flush printed output and test for an error condition. The
setError() method is used to set an error condition. PrintWriter provides support for printing
primitive data types, character arrays, strings, and general objects. Objects are converted to a string
(via the inherited or overridden toString() method) before being printed.

The Randomaccessfile Class

The RandomAccessFile class provides the capability to perform I/O directly to specific locations within
a file. The name random access comes from the fact that data can be read from or written to random
locations within a file rather than as a continuous stream of information. Random access is supported
through the seek() method, which allows the pointer corresponding to the current file position to be set
to arbitrary locations within the file.
RandomAccessFile implements both the DataInput and DataOuput interfaces. This provides the
capability to perform I/O using primitive data types.
RandomAccessFile also supports basic file read/write permissions, enabling files to be accessed in
read-only or read-write modes. A mode stream argument is passed to the RandomAccessFile
constructor as r or rw, indicating read-only and read-write file access. The read-only access attribute
may be used to prevent a file from being inadvertently modified.
RandomAccessFile introduces several new methods besides those inherited from Object and
implemented from DataInput and DataOutput. These methods include seek(),
getFilePointer(), and length(). The seek() method sets the file pointer to a particular location
within the file. The getFilePointer() method returns the current location of the file pointer. The
length() method returns the length of the file in bytes.

The RandomIOApp Program

The RandomIOApp program provides a simple demonstration of the capabilities of random-access I/O.
It writes a boolean, int, char, and double value to a file and then uses the seek() method to seek
to offset location 1 within the file. This is the position after the first byte in the file. It then reads the int,
char, and double values from the file and displays them to the console window. Next, it moves the file
pointer to the beginning of the file and reads the boolean value that was first written to the file. This
value is also written to the console window. The source code of the RandomIOApp program is shown in
Listing 15.8.

RandomioappListing 15.8: The Source Code of the Program

- 279



import java.io.*;

public class RandomIOApp {

public static void main(String args[]) throws IOException {
RandomAccessFile file = new RandomAccessFile("test.txt","rw");
file.writeBoolean(true);
file.writeInt(123456);
file.writeChar('j');
file.writeDouble(1234.56);
// Use seek() to move to a specific file location
file.seek(1);
System.out.println(file.readInt());
System.out.println(file.readChar());
System.out.println(file.readDouble());
file.seek(0);
System.out.println(file.readBoolean());
file.close();

}

}
Although the processing performed by RandomIOApp is quite simple, it illustrates how random I/O
enables you to move the file pointer to various locations within a file to directly access values and
objects contained within the file.

The program's output is as follows:

123456

j

1234.56

true

The Streamtokenizer Class

The StreamTokenizer class is used by parsers to convert an input character stream into a stream of
lexical tokens. It uses special methods to identify parser parameters, such as ordinary, whitespace,
quote, and comment characters. These methods also enable and disable number and end-of-line
parsing.
Several variables are defined for the StreamTokenizer class, four of which are constant class
variables. The TT_EOF, TT_EOL, TT_NUMBER, and TT_WORD constants are used to identify the type of
input token encountered when parsing the input stream. The ttype variable is set either to one of these

- 280



constants or to a single character based on the kind of token that is read from the input stream. The
TT_ constants are used to indicate a number, word, end of line, or end of file. When a word token is
read, the actual word is stored in the sval variable and ttype is set to TT_WORD. When a number
token is read, its value is stored in the nval variable and ttype is set to TT_NUMBER. When other
special characters, such as @ or *, are read from the input stream, they are assigned directly to the
ttype variable.
The StreamTokenizer constructor takes a Reader object as an argument and generates a
StreamTokenizer object. The StreamTokenizer access methods can be divided into two groups:
parser parameter-definition methods and stream-processing methods.
The parser parameter-definition methods are used to control the operation of the parser. The
commentChar(),slashSlashComments(), and slashStarComments() methods are used to
define comments. Comments are ignored by the parser. The
whitespaceChars(),wordChars(),quoteChar(),ordinaryChar(), and ordinaryChars()
methods are used to set the parser's token-generation parameters. The parseNumbers() and
eolIsSignificant() methods toggle number and end-of-line parsing. The lowerCaseMode()
method controls whether input words are converted to lowercase, and the resetSyntax() method is
used to reset the syntax table, causing all characters to be treated as special characters.
The stream-processing methods are used to read tokens from the input stream, push tokens back out
onto the input stream, and return the current line number associated with the input stream. The
nextToken() method is used to get the next token from the input stream. The pushBack() method
pushes the current token back out onto the input stream. The lineno() method returns the current line
number associated with the input stream. The toString() method of class Object is overwritten to
allow printing of the current token.

Chapter Summary

This chapter covered the classes and interfaces of java.io that are used to perform input and output.
You explored the input and output class hierarchy and learned how to use stream filters to simplify I/O
processing. You learned how the Reader and Writer classes support character-oriented I/O. You also
learned how to perform random-access I/O and how to access a stream's character encoding. The
following review questions and exam questions will let you know how well you understand this material
and will give you an idea of how you'll do in related exam questions. They'll also indicate which material
you need to study further.

Key Terms

.
Stream
.
Filter
.
Reader
.
Writer
.
Unicode
.
Character encoding
.
Serialization
Review Questions

1.
What is the difference between the Reader/Writer class hierarchy and the
InputStream/OutputStream class hierarchy?
2.
What an I/O filter?
3.
What is the purpose of the File class?
4.
What interface must an object implement before it can be written to a stream as an
object?
5.
What is the difference between the File and RandomAccessFile classes?
6.
What class allows you to read objects directly from a stream?
7.
What value does read() return when it has reached the end of a file?
8.
What value does readLine() return when it has reached the end of a file?
9.
How many bits are used to represent Unicode, ASCII, UTF-16, and UTF-8 characters?
- 281



10. What is your platform's default character encoding?
Exam Questions

1.
Which of the following are true?
A. The InputStream and OutputStream classes are byte-oriented.
B. The ObjectInputStream and ObjectOutputStream classes do not
support serialized object input and output.
C. The Reader and Writer classes are character-oriented.
D. The Reader and Writer classes are the preferred solution to serialized
object output.
2.
How many bytes does the following program write to temp.txt?
3. import java.io.*;
4.
5. public class TestIOApp {
6. public static void main(String args[]) throws IOException {
7. FileOutputStream outStream = new FileOutputStream("test.txt");
8. String s = "test";
9. for(int i=0;i10. outStream.write(s.charAt(i));
11. outStream.close();
12. }
}

A.
2 bytes
B.
4 bytes
C.
8 bytes
D.
16 bytes
13. Which of the following are true about I/O filters?
A.
Filters are supported on input, but not on output.
B.
Filters are supported by the InputStream/OutputStream class
hierarchy, but not by the Reader/Writer class hierarchy.
C.
Filters read from one stream and write to another.
D.
A filter may alter data that is read from one stream and written to another.
14. Which of the following are true?
A.
Any Unicode character is represented using 16 bits.
B.
Seven bits are needed to represent any ASCII character.
C.
UTF-8 characters are represented using only eight bits.
D.
UTF-16 characters are represented using only 16 bits.
15. Which of the following are true?
A. The Serializable interface is used to identify objects that may be
written to an output stream.
B. The Externalizable interface is implemented by classes that control the
way in which their objects are serialized.
C. The Serializable interface extends the Externalizable interface.
D. The Externalizable interface extends the Serializable interface.
16. Which of the following are true about the File class?
A. A File object can be used to change the current working directory.
B. A File object can be used to access the files in the current working
directory.
C. When a File object is created, a corresponding directory or file is created
in the local file system.
D.
File objects are used to access files and directories on the local file
system.
- 282


E.
File objects can be garbage collected.
F.
When a File object is garbage collected, the corresponding file or
directory is deleted.
17. What output is displayed by the following program?
18. import java.io.*;
19.
20. public class TestIOApp {
21. public static void main(String args[]) throws IOException {
22. StringReader stringin = new StringReader("test");
23. LineNumberReader in = new LineNumberReader(stringin);
24. PrintWriter out = new PrintWriter(System.out);
25. out.println(in.readLine());
26. out.flush();
27.
}
}
A.
test
B.
1. test
C.
1: test
D.
1 test
28. What output is displayed by the following program?
29. import java.io.*;
30.
31. public class TestIOApp {
32. public static void main(String args[]) throws IOException {
33. RandomAccessFile file = new RandomAccessFile("test.txt","rw");
34. file.writeBoolean(true);
35. file.writeInt(123456);
36. file.writeInt(7890);
37. file.writeLong(1000000);
38. file.writeInt(777);
39. file.writeFloat(.0001f);
40. file.seek(5);
41. System.out.println(file.readInt());
42. file.close();
43.
}
}
A.
123456
B.
7890
C.
1000000
D.
777
E.
.0001
44. How do you create a Reader object from an InputStream object?
A. Use the static createReader() method of the InputStream class.
B. Use the static createReader() method of the Reader class.
C. Create an InputStreamReader object, passing the InputStream object
as an argument to the InputStreamReader constructor.
D. Create an OutputStreamReader object, passing the InputStreamobject as an argument to the OutputStreamReader constructor.
45. Which of the following are true?
- 283



A.
Writer classes can be used to write characters to output streams using
different character encodings.
B.
Writer classes can be used to write Unicode characters to output
streams?
C.
Writer classes have methods that support the writing of the values of any
Java primitive type to output streams.
D.
Writer classes have methods that support the writing of objects to output
streams.
Answers to Review Questions

1.
The Reader/Writer class hierarchy is character-oriented, and the
InputStream/OutputStream class hierarchy is byte-oriented.
2.
An I/O filter is an object that reads from one stream and writes to another, usually
altering the data in some way as it is passed from one stream to another.
3.
The File class is used to create objects that provide access to the files and directories
of a local file system.
4.
An object must implement the Serializable or Externalizable interface before it
can be written to a stream as an object.
5.
The File class encapsulates the files and directories of the local file system. The
RandomAccessFile class provides the methods needed to directly access data
contained in any part of a file.
6.
The ObjectInputStream class supports the reading of objects from input streams.
7.
The read() method returns -1 when it has reached the end of a file.
8.
The readLine() method returns null when it has reached the end of a file.
9.
Unicode requires 16 bits and ASCII require 7 bits. Although the ASCII character set uses
only 7 bits, it is usually represented as 8 bits. UTF-8 represents characters using 8, 16,
and 18 bit patterns. UTF-16 uses 16-bit and larger bit patterns.
10. If you are running Java on English Windows platforms, it is probably Cp1252. If you are
running Java on English Solaris platforms, it is most likely 8859_1.
Answers to Exam Questions

1.
A and C. The ObjectInputStream and ObjectOutputStream classes are the
preferred classes for performing serialized object I/O.
2.
B. The "test" string is written as 4 bytes.
3.
C and D. Filters are supported on both input and output and by the
InputStream/OutputStream and Reader/Writer class hierarchies.
4.
A and B. UTF-8 and UTF-16 are multi-byte formats of variable length.
5.
A, B and D. Externalizable extends Serializable.
6.
B, D, and E. File does not provide any methods to change the current working
directory. The creation of a File object does not result in the creation of a
corresponding directory of file in the local file system. The garbage collection of a File
object does not normally have any effect on the local file system.
7.
A. LineNumberReader does not add line numbers to the input content. It makes them
available through its getLineNumber() method.
8.
B. The number 7890 is stored at file location 5 because the previously written boolean
and int values occupy 5 bytes.
9.
C. The InputStreamReader class provides a constructor for creating Reader objects
from InputStream objects.
10. A and B. Writer classes are character-oriented and do not support other primitive
types or objects.

No comments: