Download No Slide Title

Document related concepts
no text concepts found
Transcript
Chapter 14: Files
Chapter 14
Files
Java Programming
FROM THE BEGINNING
1
Chapter 14: Files
14.1 Files and Streams
• A file is a collection of related data that is given a
name and placed on a storage medium.
• A file can be a place to keep data for a long period of
time, or it can be used for temporary storage.
• Files can be stored on a variety of media, including
hard drives, floppy disks, CD-ROMs, and tapes.
• Files can also be transmitted in various ways, such as
over a computer network.
• All files are the same in one important respect: they
consist of bytes.
Java Programming
FROM THE BEGINNING
2
Chapter 14: Files
How Files Are Stored
• One way to see the sizes of files is to use the dir
command in Windows:
Volume in drive C has no label
Volume Serial Number is 07CE-0C08
Directory of C:\programs\lottery
.
<DIR>
..
<DIR>
LOTTER~1 JAV
LOTTER~1 CLA
2 file(s)
2 dir(s)
12-20-99 1:02p
12-20-99 1:02p
283 12-20-99 1:04p
511 12-20-99 1:04p
794 bytes
12,802.72 MB free
.
..
Lottery.java
Lottery.class
• The Lottery.java file contains 283 bytes, and the
Lottery.class file contains 511 bytes.
Java Programming
FROM THE BEGINNING
3
Chapter 14: Files
How Files Are Stored
• In some files, each byte represents a character. In
other files, the bytes mean other things.
• Suppose that a file consists of four bytes:
• Some possible meanings:
– The bytes represent the ASCII characters J, a, v, and a.
– The bytes represent a single integer.
– The first two bytes represent a short integer, and the second
two represent another short integer.
– The bytes represent a single float value.
Java Programming
FROM THE BEGINNING
4
Chapter 14: Files
How Files Are Stored
• Ways to leave hints about the contents of a file:
– The file’s extension
– A “marker” in the file itself, usually at the beginning
• In Windows, an executable file begins with two
special bytes containing the ASCII codes for the
letters M and Z.
• In Unix, an executable file begins with a “magic
number.” When the user tries to execute a
program, Unix first checks for the magic number.
Java Programming
FROM THE BEGINNING
5
Chapter 14: Files
Text Files Versus Binary Files
• Files fall into two categories:
– In a text file, the bytes represent characters in some
character set, such as ASCII or Unicode.
– In a binary file, the bytes don’t necessarily represent
characters (although some of them may).
Java Programming
FROM THE BEGINNING
6
Chapter 14: Files
Text Files Versus Binary Files
• Text files have two characteristics that binary files
don’t possess.
• First, text files are divided into lines.
• In Windows, the end-of-line marker is a carriagereturn character ('\r') followed immediately by
a line-feed character ('\n').
• In Unix, the end-of-line marker is a single linefeed character.
• The Macintosh operating system uses a single
carriage-return character.
Java Programming
FROM THE BEGINNING
7
Chapter 14: Files
Text Files Versus Binary Files
• Second, text files may contain a special “end-offile” marker.
• In Windows, the marker is '\u1a' (Ctrl-Z). CtrlZ doesn’t have to be present, but if it is, it marks
the end of the file.
• In a binary file, there’s no “end-of-line” or “endof-file” marker; all bytes are treated equally.
Java Programming
FROM THE BEGINNING
8
Chapter 14: Files
Text Files Versus Binary Files
• Suppose that a Windows text file contains the
following lines:
Java
rules!
• The bytes in the file, shown as hexadecimal codes:
Java Programming
FROM THE BEGINNING
9
Chapter 14: Files
Streams
• Programs that work with files will need to use the
java.io package.
• The names of many java.io classes include the
word “stream.”
• A stream is an abstraction that represents any
“file-like” source of input or destination for
output.
• A stream object may be capable of reading from
anything that resembles a file or writing to
anything that resembles a file.
Java Programming
FROM THE BEGINNING
10
Chapter 14: Files
Streams
• Classes whose names end with Stream are subclasses of
InputStream and OutputStream:
• System.out and System.err are instances of the
PrintStream class.
Java Programming
FROM THE BEGINNING
11
Chapter 14: Files
Streams
• Other classes have names that end with Reader
or Writer.
• These classes are subclasses of Reader and
Writer:
Java Programming
FROM THE BEGINNING
12
Chapter 14: Files
Streams
• The reader and writer classes are designed to help
with a common problem: Java stores characters in
Unicode, whereas most software assumes that
characters are stored in ASCII form.
• An instance of a Reader class solves the problem
by automatically converting bytes to Unicode
characters during input.
• Similarly, an instance of a Writer class will
convert Unicode characters to single bytes during
output.
Java Programming
FROM THE BEGINNING
13
Chapter 14: Files
Stream Layering
• The first step in working with a file is creating an
object that represents the file.
• Operations can then be performed on the file by
calling instance methods.
• Many of the classes java.io are designed to be
“layered,” with two or more objects involved.
• Calling a method that belongs to one object
triggers a call to an “underlying” object, which
may in turn call a method that belongs to a third
object.
Java Programming
FROM THE BEGINNING
14
Chapter 14: Files
Stream Layering
• For example, to write characters to a file, an
instance of the FileWriter class will be
needed.
• This class isn’t very efficient by itself, so a
BufferedWriter object will need to be
layered on top of the FileWriter object.
• The methods in the BufferedWriter class
aren’t very convenient to use, however, so a
PrintWriter object will need to be layered on
top of the BufferedWriter object.
Java Programming
FROM THE BEGINNING
15
Chapter 14: Files
Stream Layering
• A diagram showing the layering of the three
classes:
Java Programming
FROM THE BEGINNING
16
Chapter 14: Files
Stream Layering
• Calling a method that belongs to PrintWriter
in turn calls a method (or methods) belonging to
BufferedWriter, which then calls a method(s)
belonging to FileWriter.
• Layering provides flexibility: the programmer can
combine classes in many different ways to get the
right blend of efficiency and convenience.
Java Programming
FROM THE BEGINNING
17
Chapter 14: Files
Working with Files
• Working with a file involves three steps:
– Open the file
– Perform operations on the file
– Close the file
Java Programming
FROM THE BEGINNING
18
Chapter 14: Files
Opening a File
• Opening a file requires specifying the file’s name
and possibly its location.
• Opening a file is done by creating an instance of
an appropriate stream class (or—in the case of a
text file—a reader or writer class).
• This object represents the file within the program.
• Creating a FileOutputStream object opens a
binary file for writing:
FileOutputStream out =
new FileOutputStream(filename);
Java Programming
FROM THE BEGINNING
19
Chapter 14: Files
Opening a File
• Opening a file for input will fail—causing an
exception to be thrown—unless the file already
exists.
• When an existing file is opened for output, the file
is normally truncated—the bytes already in the
file are lost.
• Attempting to open a nonexistent file for output
will cause the file to be created. Either way, the
file is empty to begin with.
Java Programming
FROM THE BEGINNING
20
Chapter 14: Files
Performing Operations on a File
• File operations, such as reading data or writing
data, are performed by calling instance methods
that belong to the stream object’s class.
• The operations that can be performed on the out
object are dictated by the methods in
FileOutputStream (and its superclasses).
• One of these methods, named write, is capable
of writing a single byte:
out.write(b);
Java Programming
FROM THE BEGINNING
// Writes the byte b
21
Chapter 14: Files
Closing a File
• A file should be closed when no more operations
will be performed on it.
• Closing a file is done by calling the close
method:
out.close();
• All stream, reader, and writer classes support the
close method (either by providing it or
inheriting it).
Java Programming
FROM THE BEGINNING
22
Chapter 14: Files
Obtaining File Names
• Ways to supply a file name to a program:
– Build the name into the program
– Prompt the user to enter the name
– Obtain the name from the command line
• An example of obtaining file names from the
command line:
java CopyFile file1 file2
• args[0] will contain the name of the file to be
copied. args[1] will contain the name of the file
that will store the copy.
Java Programming
FROM THE BEGINNING
23
Chapter 14: Files
Buffering and Flushing
• A buffer is a place where data is stored
temporarily, usually on its way from one place to
another.
• Buffers are common when working with files.
• When a program calls a method that writes to a
file, the data being written usually goes into a
buffer first.
• When the buffer is full, all the data in the buffer is
then transferred to the file, and the buffer becomes
empty.
Java Programming
FROM THE BEGINNING
24
Chapter 14: Files
Buffering and Flushing
• Similar actions take place when data is read from
a file: a large chunk of data is first transferred to a
buffer.
• The program then obtains small portions of the
data from the buffer.
• When the buffer becomes empty, another large
chunk is read from the file.
Java Programming
FROM THE BEGINNING
25
Chapter 14: Files
Buffering and Flushing
• Using buffers for input and output can
dramatically improve a program’s performance.
• Transferring information to or from a disk drive is
a relatively slow operation.
• Reading a byte from a buffer or storing a byte into
a buffer takes hardly any time at all.
• It takes time to transfer the buffer contents to or
from disk, but one large data transfer is much
faster than many small ones.
Java Programming
FROM THE BEGINNING
26
Chapter 14: Files
Buffering and Flushing
• Java’s stream classes are designed to perform
buffering without any action on the programmer’s
part.
• Occasionally, though, it’s necessary to take a more
active role.
• Normally, data written to a file goes into a buffer
first.
• The buffer is flushed (written to the file)
automatically when it’s full or the file is closed.
Java Programming
FROM THE BEGINNING
27
Chapter 14: Files
Buffering and Flushing
• The buffer can be flushed manually by calling the
flush method:
out.flush();
out can be an output stream or writer object
• Calling flush ensures that data is written to a file
as soon as possible, where it will be safe.
• All output stream and writer classes support the
flush method.
Java Programming
FROM THE BEGINNING
28
Chapter 14: Files
File Pointers
• For each open file, Java maintains a file pointer,
which keeps track of which byte will be the next
to be read or written.
• If a file is opened for reading, the file pointer will
be at the beginning:
Java Programming
FROM THE BEGINNING
29
Chapter 14: Files
File Pointers
• If one byte is now read from the file, the file pointer
will advance automatically to the next byte:
• The file pointer will eventually advance past the last
byte in the file—a condition known as end of file.
• It’s important to test for this condition each time input
is read from a file.
Java Programming
FROM THE BEGINNING
30
Chapter 14: Files
File Pointers
• Writing to a file is similar: Java keeps track of the
current position in the file and advances the file
pointer after each write operation.
• Normally, writing starts at the beginning of a file.
• In some cases, however, it may be necessary to
append data to the end of the file, thereby
preserving the file’s original contents.
Java Programming
FROM THE BEGINNING
31
Chapter 14: Files
File Pointers
• Reading or writing a file from beginning to end is
called sequential access.
• Java also supports a different type of access,
known as random access.
• Random access allows a program to move freely
within a file.
• Random access requires the use of the
RandomAccessFile class.
Java Programming
FROM THE BEGINNING
32
Chapter 14: Files
14.2 The File Class
• File is one of the most fundamental classes in
the java.io package.
• A File object represents a file stored on disk or
some other medium.
• The File class allows a program to work with
the properties of a file, not the contents of the file.
• File also provides a few basic file operations,
including deleting a file and renaming a file.
Java Programming
FROM THE BEGINNING
33
Chapter 14: Files
Creating File Objects
• There are several ways to create a File object.
• One File constructor expects a string containing
the file’s name:
File f = new File("Lottery.java");
Java will try to locate the file in the current
directory.
• To work with a file in a different directory, path
information will need to be included in the string:
File f =
new File("c:\\programs\\lottery\\Lottery.java");
Java Programming
FROM THE BEGINNING
34
Chapter 14: Files
Creating File Objects
• The path and the file name can be supplied as
separate arguments:
File f = new File("c:\\programs\\lottery",
"Lottery.java");
• In Windows, two backslash characters are needed
to separate directory names.
• Java would interpret a single backslash character
as the beginning of an escape sequence.
Java Programming
FROM THE BEGINNING
35
Chapter 14: Files
Creating File Objects
• Another way to solve the backslash problem is to
use a slash character instead of a backslash to
separate directory names:
File f =
new File("c:/programs/lottery/Lottery.java");
• Although the backslash is the normal character for
separating directory names in Windows, ordinary
slashes will also work within Java programs.
Java Programming
FROM THE BEGINNING
36
Chapter 14: Files
File Properties
• The File class provides a set of “query” methods that
return information about a file:
Description
Action
boolean canRead()
Returns true if the program can read
from this file.
boolean canWrite()
Returns true if the program can write
to this file.
boolean exists()
Returns true if this file exists.
boolean isDirectory() Returns true if this file is a directory.
boolean isFile()
Returns true if this file is normal (not
a directory).
long length()
Returns the length of this file in bytes.
String[] list()
Returns an array of strings containing
the names of the files in this directory.
Java Programming
FROM THE BEGINNING
37
Chapter 14: Files
Program: Determining the
Properties of a File
• The FileProperties program prompts the
user for the name of a file and then displays the
file’s properties.
• Output of the program when asked to show the
properties of the Lottery.java file:
Enter a file name: Lottery.java
File can be read
File can be written
File exists
File is normal
Length of file: 283
Java Programming
FROM THE BEGINNING
38
Chapter 14: Files
Program Behavior
• Output when asked to show the properties of the
directory containing Lottery.java:
Enter a file name: c:\programs\lottery
File can be read
File can be written
File exists
File is a directory
Length of file: 0
Java Programming
FROM THE BEGINNING
39
Chapter 14: Files
FileProperties.java
// Displays the properties of a file
import java.io.*;
import jpb.*;
public class FileProperties {
public static void main(String[] args) {
// Prompt user to enter file name
SimpleIO.prompt("Enter a file name: ");
String fileName = SimpleIO.readLine();
// Create a File object
File f = new File(fileName);
Java Programming
FROM THE BEGINNING
40
Chapter 14: Files
// Display properties of file
if (f.canRead())
System.out.println("File can be read");
if (f.canWrite())
System.out.println("File can be written");
if (f.exists())
System.out.println("File exists");
if (f.isDirectory())
System.out.println("File is a directory");
if (f.isFile())
System.out.println("File is normal");
System.out.println("Length of file: " + f.length());
}
}
Java Programming
FROM THE BEGINNING
41
Chapter 14: Files
Program: Listing the Files in a Directory
• The list method returns an array containing the
names of all files in a particular directory.
• The ListFiles program uses list to display
the names of the files in the current directory
(represented by the file name ".").
• Output of the program when used to list the files
in the c:\programs\lottery directory:
Lottery.java
Lottery.class
Java Programming
FROM THE BEGINNING
42
Chapter 14: Files
ListFiles.java
// Displays a list of all files in the current directory
import java.io.*;
public class ListFiles {
public static void main(String[] args) {
// Obtain a list of all files in the current directory
File currentDirectory = new File(".");
String[] fileNames = currentDirectory.list();
// Display each name in the list
for (int i = 0; i < fileNames.length; i++)
System.out.println(fileNames[i]);
}
}
Java Programming
FROM THE BEGINNING
43
Chapter 14: Files
File Operations
• In addition to query methods, the File class also
provides a few basic operations on files:
Description
Action
boolean delete()
Deletes this file.
boolean mkdir()
Creates a directory
corresponding to this File
object.
boolean renameTo(File dest) Renames this file to the name
specified by dest.
• All three methods return true if they are
successful and false if they are not successful.
Java Programming
FROM THE BEGINNING
44
Chapter 14: Files
Program: Renaming the Files in a Directory
• The RenameFiles program displays the names
of all files in the current directory, one by one, and
allows the user to change the names of selected
files.
• A sample session with the program:
Rename Lottery.java (y/n)? n
Rename Lottery.class (y/n)? y
Enter new name: Lottery2.class
Java Programming
FROM THE BEGINNING
45
Chapter 14: Files
RenameFiles.java
// Renames selected files in the current directory
import java.io.*;
import jpb.*;
public class RenameFiles {
public static void main(String[] args) {
// Obtain a list of all files in the current directory
File currentDirectory = new File(".");
String[] fileNames = currentDirectory.list();
// Process each name in the list
for (int i = 0; i < fileNames.length; i++) {
// Ask user whether or not to rename file
SimpleIO.prompt("Rename " + fileNames[i] + " (y/n)? ");
String response = SimpleIO.readLine();
Java Programming
FROM THE BEGINNING
46
Chapter 14: Files
// If the answer is "y" or "Y", ask for new name and
// then call renameTo
if (response.equalsIgnoreCase("y")) {
SimpleIO.prompt("Enter new name: ");
String newName = SimpleIO.readLine();
File oldFile = new File(fileNames[i]);
File newFile = new File(newName);
boolean successful = oldFile.renameTo(newFile);
if (!successful)
System.out.println("Could not rename " +
fileNames[i] + " to " +
newName);
}
}
}
}
Java Programming
FROM THE BEGINNING
47
Chapter 14: Files
14.3 Reading and Writing Bytes
• The FileInputStream and
FileOutputStream classes are used to read
and write single bytes or blocks of bytes.
• These classes are useful for writing file utilities,
such as a program that makes a copy of a file.
Java Programming
FROM THE BEGINNING
48
Chapter 14: Files
Writing Bytes
• Opening a file for writing is done by creating a
FileOutputStream object.
• Common FileOutputStream constructors:
Description
FileOutputStream(
String name)
FileOutputStream(
String name,
boolean append)
FileOutputStream(
File file)
Java Programming
FROM THE BEGINNING
Action
Creates a FileOutputStream object
representing the file with the specified name.
Creates a FileOutputStream object
representing the file with the specified name.
If append is true, bytes will be written to
the end of the file rather than the beginning.
Creates a FileOutputStream object
representing the specified File object.
49
Chapter 14: Files
Writing Bytes
• The first constructor needs a file name (possibly
containing path information) as its argument:
FileOutputStream out =
new FileOutputStream(fileName);
• The second constructor is used to specify that any
bytes written to the file should be appended to the
file, thereby preserving the file’s original contents.
• The third constructor takes a File object instead
of a file name.
Java Programming
FROM THE BEGINNING
50
Chapter 14: Files
Writing Bytes
• Using the FileOutputStream constructor to
open an existing file causes the file to be
truncated.
• The contents of the file is preserved, however, if
the second constructor is used and the value of
append is true.
• If the FileOutputStream constructor is given
the name of a file that doesn’t exist, the file will be
created.
Java Programming
FROM THE BEGINNING
51
Chapter 14: Files
Writing Bytes
• If a file can’t be opened for writing, the
FileOutputStream constructor will throw
IOException.
• Because IOException is a checked exception,
the constructor call will need to be enclosed within
a try block.
• Starting with version 1.2 of the JDK, the
FileOutputStream constructor throws
FileNotFoundException instead of
IOException.
Java Programming
FROM THE BEGINNING
52
Chapter 14: Files
Writing Bytes
• The primary methods provided by
FileOutputStream are all named write.
• These methods throw IOException if an error occurs.
• The first version of write writes a single byte:
byte outputByte;
…
out.write(outputByte);
• The second version writes a block of bytes stored in an
array:
byte[] buffer = new byte[512];
…
out.write(buffer);
Java Programming
FROM THE BEGINNING
53
Chapter 14: Files
Writing Bytes
• The third version is also designed to write a block
of bytes. It requires two additional arguments:
byte[] buffer = new byte[512];
int count;
…
out.write(buffer, 0, count);
• The second argument is an offset into the array;
the value 0 indicates that the byte at position 0 will
be the first to be written.
• The third argument is the number of bytes to
write.
Java Programming
FROM THE BEGINNING
54
Chapter 14: Files
Writing Bytes
• Most operations on a FileOutputStream
object can throw IOException.
• An attempt to open a file for writing might fail
because of an invalid path, no permission to write
to the file, and so on.
• Attempts to write to the file could fail because the
physical device has a problem or because the
device is full.
Java Programming
FROM THE BEGINNING
55
Chapter 14: Files
Writing Bytes
• A program that works with files should specify
what action should be taken for each potential
failure.
• Because IOException is a checked exception,
possible errors can’t simply be ignored.
• In many cases, the program won’t be able to
continue execution, but it should at least display a
meaningful error message.
• In particular, it’s a good idea to display the name
of the file that has caused the problem.
Java Programming
FROM THE BEGINNING
56
Chapter 14: Files
Reading Bytes
• Reading bytes from a file requires the creation of a
FileInputStream object.
• Common FileInputStream constructors:
Description
Action
FileInputStream( Creates a FileInputStream object
String name)
representing the file with the specified name.
FileInputStream( Creates a FileInputStream object
File file)
representing the specified File object.
• The first constructor requires a file name:
FileInputStream in = new FileInputStream(fileName);
• Both constructors throw FileNotFoundException if the
specified file can’t be opened for input.
Java Programming
FROM THE BEGINNING
57
Chapter 14: Files
Reading Bytes
• The primary methods provided by FileInputStream
are all named read:
Description
Action
int read()
Reads a byte, returning it in int form.
int read(byte[] b) Reads bytes into b until the array is full
or the end of the file has been reached.
Returns the number of bytes read.
int read(byte[] b, Reads up to len bytes into the array b,
int off, starting at the position indicated by off.
int len) Returns the number of bytes read.
• All three methods throw IOException if an error occurs.
• If any read method fails to read any input because it has
reached the end of the file, it returns –1.
Java Programming
FROM THE BEGINNING
58
Chapter 14: Files
Reading Bytes
• The first version of the read method reads a
single byte:
int byteValue = in.read();
• read returns an int value, not a byte value, so
the return value should be stored in an int
variable.
• The variable should then be tested to see if it is
equal to –1 (indicating that no byte could be read).
• If the variable is not equal to –1, its value can then
be cast to byte form.
Java Programming
FROM THE BEGINNING
59
Chapter 14: Files
Reading Bytes
• A loop that reads all the bytes in a file:
while (true) {
int byteValue = in.read();
if (byteValue == -1)
break; // End of file reached
byte inputByte = (byte) byteValue;
…
}
• In some cases, it’s possible to omit the cast and
just leave the byte in the original int variable.
Java Programming
FROM THE BEGINNING
60
Chapter 14: Files
Reading Bytes
• The second version of read reads bytes into an array
until it’s full or no more bytes can be read:
byte[] buffer = new byte[512];
…
int count = in.read(buffer);
• The third version specifies where the bytes should be
stored in the array and how many bytes can be read.
• After calling either version of read, it’s important to
test whether count has the value –1.
• If so, no bytes could be read because the method
encountered the end of the file.
Java Programming
FROM THE BEGINNING
61
Chapter 14: Files
Program: Copying a File
• The CopyFile program will copy a file.
• The FileInputStream and
FileOutputStream classes are perfect for this
kind of program, which has no knowledge of what
the original file contains.
• The user will supply the names of the original file
and the new file on the command line:
java CopyFile source destination
source is the name of the original file, and
destination is the name of the new file.
Java Programming
FROM THE BEGINNING
62
Chapter 14: Files
Design of the CopyFile Program
• Strategy:
– Check that there are two command-line arguments.
– Create a FileInputStream object to represent the
source file.
– Create a FileOutputStream object to represent the
destination file.
– Use a loop to read a block of bytes from the
FileInputStream object and write the block to the
FileOutputStream object.
– Close both files.
Java Programming
FROM THE BEGINNING
63
Chapter 14: Files
Exceptions in the CopyFile Program
• Checked exceptions that can occur:
– The FileInputStream constructor can throw
FileNotFoundException.
– The FileOutputStream constructor can throw
IOException (or FileNotFoundException).
– The read method in FileInputStream can throw
IOException.
– The write method in FileOutputStream can
throw IOException.
– The close methods in FileInputStream and
FileOutputStream can throw IOException.
Java Programming
FROM THE BEGINNING
64
Chapter 14: Files
Exceptions in the CopyFile Program
• Instead of having a separate try block and
catch block for each exception, most of the
program will be enclosed within a single try
block.
• After the try block will come two catch
blocks, one for FileNotFoundException
and one for IOException.
Java Programming
FROM THE BEGINNING
65
Chapter 14: Files
CopyFile.java
// Copies one file into another. The names of both files must
// be specified on the command line.
import java.io.*;
public class CopyFile {
public static void main(String[] args) {
// Terminate program if number of command-line arguments
// is wrong
if (args.length != 2) {
System.out.println("Usage: java CopyFile source dest");
System.exit(-1);
}
Java Programming
FROM THE BEGINNING
66
Chapter 14: Files
try {
// Open source file for input and destination file for
// output
FileInputStream source = new FileInputStream(args[0]);
FileOutputStream dest = new FileOutputStream(args[1]);
// Set up a 512-byte buffer
byte[] buffer = new byte[512];
// Copy bytes from the source file to the destination
// file, 512 bytes at a time
while (true) {
int count = source.read(buffer);
if (count == -1)
break;
dest.write(buffer, 0, count);
}
Java Programming
FROM THE BEGINNING
67
Chapter 14: Files
// Close source and destination files
source.close();
dest.close();
} catch (FileNotFoundException e) {
System.out.println("File cannot be opened");
} catch (IOException e) {
System.out.println("I/O error during copy");
}
}
}
Java Programming
FROM THE BEGINNING
68
Chapter 14: Files
14.4 Advanced Exception-Handling
• The constructors and methods of the stream
classes throw a variety of checked exceptions.
• Section 8.1 covered the rudiments of exceptionhandling, but a more detailed knowledge is needed
in order to write programs that use files.
Java Programming
FROM THE BEGINNING
69
Chapter 14: Files
The Hierarchy of Exception Classes
• For each kind of exception, the Java API provides
a corresponding class, such as IOException.
• A class named Throwable is the superclass
(directly or indirectly) for all exception classes.
• The Throwable class has only two direct
subclasses: Error and Exception.
• Classes that represent specific kinds of exceptions
are subclasses of either Error or Exception.
Java Programming
FROM THE BEGINNING
70
Chapter 14: Files
The Hierarchy of Exception Classes
• A diagram showing how the exception classes are
descended from Throwable:
• This diagram shows only a few of Throwable’s
many subclasses.
Java Programming
FROM THE BEGINNING
71
Chapter 14: Files
The Hierarchy of Exception Classes
• Exception classes that extend Error represent
unrecoverable errors, such as the Java interpreter
failing to load a class or running out of memory.
• Classes that extend Exception represent problems
that can potentially be handled within a program.
• Subclasses of Error or RuntimeException
represent unchecked exceptions.
• Subclasses of Exception (but not
RuntimeException) represent checked
exceptions.
Java Programming
FROM THE BEGINNING
72
Chapter 14: Files
Using Multiple catch Blocks
• The fact that exception classes are related to each
other has some interesting consequences for
writing catch blocks.
• Suppose that a try block is followed by two or
more catch blocks:
try
block
catch (exception-type identifier)
block
…
catch (exception-type identifier)
block
Java Programming
FROM THE BEGINNING
73
Chapter 14: Files
Using Multiple catch Blocks
• If an exception is thrown inside a try block, the
first catch block with a compatible exception
type will be allowed to handle the exception.
• A catch block can catch exceptions of a
specified type, as well as exceptions that belong to
a subclass of that type.
• For example, a catch block for IOException
can also catch FileNotFoundException,
which is a subclass of IOException.
Java Programming
FROM THE BEGINNING
74
Chapter 14: Files
Using Multiple catch Blocks
• More than one catch block may be capable of
handling a given exception:
try {
…
} catch (FileNotFoundException e) {
…
} catch (IOException e) {
…
}
• If a FileNotFoundException occurs, both
catch blocks can potentially handle the
exception, but only the first will be allowed to.
Java Programming
FROM THE BEGINNING
75
Chapter 14: Files
Using Multiple catch Blocks
• If catch blocks are put in the wrong order, it’s possible
that an early catch block may end up catching exceptions
that were meant for a later catch block:
try {
…
} catch
… //
} catch
… //
}
(IOException e) {
Catches FileNotFoundException as well
(FileNotFoundException e) {
Never executed!
• The second catch block can never be executed; if a
FileNotFoundException occurs in the try block,
the first catch block will handle the exception.
Java Programming
FROM THE BEGINNING
76
Chapter 14: Files
Using Multiple catch Blocks
• A catch block for IOException will catch all
exceptions that belong to subclasses of
IOException.
• Using such a catch block isn’t always
appropriate, because the program can no longer
act differently based on the particular exception.
• If a single catch block is used to catch I/O
exceptions, it’s a good idea to have it display the
message stored inside the IOException object.
Java Programming
FROM THE BEGINNING
77
Chapter 14: Files
Using Multiple catch Blocks
• It’s possible to write catch blocks that handle a
wide variety of exceptions, not just I/O exceptions.
• A catch block for Exception will catch any
exception that represents a recoverable error:
try {
…
} catch
… //
} catch
… //
}
(IOException e) {
Catches all I/O exceptions
(Exception e) {
Catches all other exceptions
Java Programming
FROM THE BEGINNING
78
Chapter 14: Files
Using Multiple catch Blocks
• Using Exception in a catch block can be
dangerous, however: the block may catch
exceptions that weren’t anticipated when the
program was designed.
• Whenever possible, use specific exception classes
in catch blocks, rather than broader classes such
as Exception.
Java Programming
FROM THE BEGINNING
79
Chapter 14: Files
finally Blocks
• After the last in a series of catch blocks, a
finally block may be present:
try
block
catch (exception-type identifier)
block
…
catch (exception-type identifier)
block
finally
block
Java Programming
FROM THE BEGINNING
80
Chapter 14: Files
finally Blocks
• The finally block is executed after the try
block terminates or the exception is caught by a
catch block.
• It must be executed even if the try block
terminates prematurely because of a control
statement (break, continue, or return).
• Typically, the finally block contains code that
closes files or performs other “cleanup” actions.
• finally can even be used without any catch
blocks.
Java Programming
FROM THE BEGINNING
81
Chapter 14: Files
The throws Clause
• Actually, it’s not always the case that checked
exceptions must be caught.
• When there’s a possibility that a checked
exception might be thrown inside a method, there
are two choices:
– Handle the exception within the method.
– Declare that the method throws the exception. Any
method that calls this one will now be responsible for
handling the exception.
Java Programming
FROM THE BEGINNING
82
Chapter 14: Files
The throws Clause
• Consider the problem of writing a helper method
that calls Java’s Thread.sleep method.
• Thread.sleep throws a checked exception
named InterruptedException.
• One approach is to handle the exception within the
new method:
static void sleep(int time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {}
}
Java Programming
FROM THE BEGINNING
83
Chapter 14: Files
The throws Clause
• The other possibility is to declare that the new
method throws InterruptedException:
static void sleep(int time)
throws InterruptedException {
Thread.sleep(time);
}
• If InterruptedException occurs, the new
method will return. The method that called it will
now be responsible for catching the exception.
• Of course, that method might also have a throws
clause.
Java Programming
FROM THE BEGINNING
84
Chapter 14: Files
The throws Clause
• If a method fails to either catch a checked
exception or declare it using throws, the
compiler will issue an error message.
• Which technique is best depends on whether or
not it is meaningful to deal with the exception
inside the method where it’s thrown.
• If so, then there’s no reason for the calling method
to know about the exception.
• Otherwise, it’s better to let the calling method
handle the exception.
Java Programming
FROM THE BEGINNING
85
Chapter 14: Files
Program: Copying a File (Revisited)
• The throws clause is sometimes used by
programmers looking for a shortcut.
• The CopyFile2 program is similar to the earlier
CopyFile program, except that it does not handle
exceptions.
• Instead, CopyFile2 declares that main throws
IOException.
• There’s no need to mention that main throws
FileNotFoundException, because
FileNotFoundException is a subclass of
IOException.
Java Programming
FROM THE BEGINNING
86
Chapter 14: Files
Program Behavior
• If an IOException (or FileNotFoundException) occurs during the execution of
CopyFile2, it will terminate with an error
message about an unhandled exception.
• From a design standpoint, it’s better to handle the
exception within the program itself, displaying an
appropriate error message and, if possible, taking
steps to recover from the exception.
Java Programming
FROM THE BEGINNING
87
Chapter 14: Files
CopyFile2.java
// Copies one file into another. The names of both files must
// be specified on the command line.
import java.io.*;
public class CopyFile2 {
public static void main(String[] args) throws IOException {
// Terminate program if number of command-line arguments
// is wrong
if (args.length != 2) {
System.out.println("Usage: java CopyFile2 source dest");
System.exit(-1);
}
// Open source file for input and destination file for
// output
FileInputStream source = new FileInputStream(args[0]);
FileOutputStream dest = new FileOutputStream(args[1]);
Java Programming
FROM THE BEGINNING
88
Chapter 14: Files
// Set up a 512-byte buffer
byte[] buffer = new byte[512];
// Copy bytes from the source file to the destination
// file, 512 bytes at a time
while (true) {
int count = source.read(buffer);
if (count == -1)
break;
dest.write(buffer, 0, count);
}
// Close source and destination files
source.close();
dest.close();
}
}
Java Programming
FROM THE BEGINNING
89
Chapter 14: Files
14.5 Reading and Writing Data Types
• The FileInputStream and FileOutputStream classes are not very convenient for reading
and writing bytes that represent specific types of data.
• The DataInputStream and DataOutputStream classes are better suited for this task.
• These classes are designed for use with binary files.
• Numbers and other types of data can be written to a
text file, but only after being converted to character
form.
Java Programming
FROM THE BEGINNING
90
Chapter 14: Files
Writing Data Types
• A DataOutputStream object can’t be created
directly from a file name.
• Instead, a FileOutputStream object is first
created, and then that object is used to create a
DataOutputStream object:
FileOutputStream fileOut =
new FileOutputStream(fileName);
DataOutputStream out =
new DataOutputStream(fileOut);
• The DataOutputStream constructor will accept
any output stream object as its argument.
Java Programming
FROM THE BEGINNING
91
Chapter 14: Files
Writing Data Types
• To shorten the code, some programmers nest the
FileOutputStream constructor inside the
DataOutputStream constructor:
DataOutputStream out =
new DataOutputStream(
new FileOutputStream(fileName));
• Operations performed on the DataOutputStream object will indirectly affect the underlying
FileOutputStream object.
• The methods in the DataOutputStream class are
capable of writing data of specific types.
Java Programming
FROM THE BEGINNING
92
Chapter 14: Files
Writing Data Types
• A partial list of DataOutputStream methods:
Description
Action
void write(int b)
Writes the value of b as a single byte.
void write(byte[] b,
Writes len bytes of the array b, startint off, int len)
ing at the position indicated by off.
void writeBoolean(
Writes the value of v as a byte containboolean v)
ing either 1 (true) or 0 (false).
void writeByte(int v)
Writes the value of v as a single byte.
void writeChar(int v)
Writes the value of v as 2 bytes.
void writeDouble(double v) Writes the value of v as 8 bytes.
void writeFloat(float v)
Writes the value of v as 4 bytes.
void writeInt(int v)
Writes the value of v as 4 bytes.
void writeLong(long v)
Writes the value of v as 8 bytes.
void writeShort(int v)
Writes the value of v as 2 bytes.
Java Programming
FROM THE BEGINNING
93
Chapter 14: Files
Writing Data Types
• All of these methods throw IOException if an
error occurs.
• An example of using writeInt to write the value
of an int variable:
out.writeInt(n);
Four bytes (the value of n in binary) will be written
to the stream.
• The other DataOutputStream methods are
called in a similar fashion.
Java Programming
FROM THE BEGINNING
94
Chapter 14: Files
Writing Strings
• Writing strings to a DataOutputStream is a
bit tricky, because a string doesn’t have a fixed
size.
• DataOutputStream has three different
methods for writing strings: writeBytes,
writeChars, and writeUTF.
• All three methods throw IOException if an
error occurs.
Java Programming
FROM THE BEGINNING
95
Chapter 14: Files
Writing Strings
• The writeBytes method writes a string as a
series of single bytes.
• The following call writes three bytes:
out.writeBytes("abc");
• The writeChars method writes a string as a
series of Unicode characters, each of which
requires two bytes.
• The following call writes six bytes:
out.writeChars("abc");
Java Programming
FROM THE BEGINNING
96
Chapter 14: Files
Writing Strings
• Reading a string that’s been written by either
writeBytes or writeChars could be
difficult, because there’s no indication in the file
itself of how many characters are in the string.
• The writeUTF method avoids this problem.
• This method uses an encoding scheme known as
UTF-8 to write a string in such a way that it can
be read later.
Java Programming
FROM THE BEGINNING
97
Chapter 14: Files
Writing Strings
• The UTF-8 encoding of a string containing ASCII
characters consists of a two-byte integer (the
length of the string), followed by the characters in
the string, each as a single byte.
• Example calls of writeUTF:
out.writeUTF("so");
out.writeUTF("far");
These calls write a total of nine bytes:
Java Programming
FROM THE BEGINNING
98
Chapter 14: Files
Writing Strings
• In UTF, non-ASCII characters (plus the null character)
are stored using two or three bytes.
• The two bytes that are written ahead of the string
represent the number of bytes in the string’s encoding,
not the original length of the string.
• The advantage of the writeUTF method is that each
string is preceded by its size, making it easy to recover
the original string when the file is read.
• The readUTF method (in the DataInputStream
class) is designed to read strings written in UTF form.
Java Programming
FROM THE BEGINNING
99
Chapter 14: Files
Reading Data Types
• In order to read data that was written to a
DataOutputStream, a DataInputStream
object is needed.
• A DataInputStream object is normally layered on
top of a FileInputStream object:
FileInputStream fileIn =
new FileInputStream(fileName);
DataInputStream in =
new DataInputStream(fileIn);
• The parameter for the DataInputStream
constructor has type InputStream.
Java Programming
FROM THE BEGINNING
100
Chapter 14: Files
Reading Data Types
• A partial list of DataInputStream methods:
Description
Action
int read(byte[] b)
Reads bytes into b until the array is
full or the end of the file has been
reached. Returns the number of bytes
read.
int read(byte[] b,
Reads up to len bytes of data into
int off,
the array b, starting at the position
int len)
indicated by off. Returns the
number of bytes read.
boolean readBoolean() Reads a single byte. Returns false
if the byte is 0; returns true
otherwise.
(continued)
Java Programming
FROM THE BEGINNING
101
Chapter 14: Files
Reading Data Types
Description
Action
byte readByte()
Reads a single byte and returns it.
char readChar()
Reads a 2-byte char value and returns it.
double readDouble() Reads an 8-byte double value and
returns it.
float readFloat() Reads a 4-byte float value and returns it.
int readInt()
Reads a 4-byte int value and returns it.
long readLong()
Reads an 8-byte long value and returns it.
short readShort() Reads a 2-byte short value and returns it.
String readUTF()
Reads a string and returns it. The string is
assumed to be stored using UTF-8
encoding.
• All these methods throw IOException if an error occurs.
Java Programming
FROM THE BEGINNING
102
Chapter 14: Files
Reading Data Types
• If one of the read methods fails to read any input
because it reaches the end of the file, it returns –1.
• Each of the other methods throws EOFException if
it fails to read the necessary number of bytes because
reaches the end of the file.
• An example of using readInt to read an int value:
int n = in.readInt();
Java Programming
FROM THE BEGINNING
103
Chapter 14: Files
14.6 Reading and Writing Characters
• To read and write text files—files that contain
character data—the preferred technique is to use
reader and writer classes.
• Reader objects are capable of translating single
bytes into the two-byte Unicode characters that
Java uses.
• Writer objects perform the opposite translation,
converting Unicode characters to single bytes.
Java Programming
FROM THE BEGINNING
104
Chapter 14: Files
Writing to a Text File
• The FileWriter class is similar to the
FileOutputStream class, except that it’s
designed for use with text files.
• As it writes characters to a file, a FileWriter
object will automatically convert each Unicode
character into a single byte.
Java Programming
FROM THE BEGINNING
105
Chapter 14: Files
Writing to a Text File
• Constructors for the FileWriter class:
Description
Action
FileWriter(
Creates a FileWriter object
String fileName) representing the file with the specified
name.
FileWriter(
Creates a FileWriter object
String fileName, representing the file with the specified
boolean append) name. If append is true, bytes will be
written to the end of the file rather than
the beginning.
FileWriter(
Creates a FileWriter object
File file)
representing the specified File object.
• IOException occurs if a file can’t be opened for output.
Java Programming
FROM THE BEGINNING
106
Chapter 14: Files
Writing to a Text File
• The FileWriter class has no methods,
although it does inherit methods for writing
characters from its superclasses.
• In most cases, it’s best to create a different kind of
object to do the actual writing to a FileWriter
object.
• The BufferedWriter class is designed for this
purpose.
• Using BufferedWriter provides greater
efficiency than using FileWriter directly.
Java Programming
FROM THE BEGINNING
107
Chapter 14: Files
Writing to a Text File
• The single-argument BufferedWriter constructor
accepts a FileWriter object (as well as other
writer objects) as its argument:
FileWriter fileOut =
new FileWriter(filename);
BufferedWriter bufOut =
new BufferedWriter(fileOut);
• BufferedWriter provides only a limited set of
methods, so it’s usually more convenient to use the
methods in the PrintWriter class instead.
• PrintWriter provides the familiar print and
println methods.
Java Programming
FROM THE BEGINNING
108
Chapter 14: Files
Writing to a Text File
• A BufferedWriter object (as well as any writer or
output stream object) can be passed to the
PrintWriter constructor:
PrintWriter out = new PrintWriter(bufOut);
• The PrintWriter class supports the print
method, which is capable of writing objects as well as
values of the primitive types:
out.print(3.14);
out.print("Testing...");
• When print is used to write an object, the object’s
toString method is called.
Java Programming
FROM THE BEGINNING
109
Chapter 14: Files
Writing to a Text File
• The PrintWriter class also provides a number
of println methods, which are used in the same
way as print:
out.println(3.14);
out.println("Testing...");
Java Programming
FROM THE BEGINNING
110
Chapter 14: Files
Reading from a Text File
• The FileReader class is used for reading
characters from a text file.
• As it reads from a file, a FileReader object
will automatically convert each byte into the
corresponding two-byte Unicode character.
• The FileReader constructors are analogous to
the FileInputStream constructors.
• Both constructors throw FileNotFoundException if the file can’t be opened for
reading.
Java Programming
FROM THE BEGINNING
111
Chapter 14: Files
Reading from a Text File
• The FileReader class inherits methods for
reading characters from its superclasses.
• In most cases, it’s best to create a BufferedReader object to do the actual reading, however.
• Using BufferedReader provides greater
efficiency than using FileReader directly.
• Also, the BufferedReader class has methods
to read whole lines of characters, not just single
characters.
Java Programming
FROM THE BEGINNING
112
Chapter 14: Files
Reading from a Text File
• The single-argument BufferedReader
constructor accepts a FileReader object (as
well as other kinds of reader objects) as its
argument:
FileReader fileIn = new FileReader(filename);
BufferedReader in = new BufferedReader(fileIn);
Java Programming
FROM THE BEGINNING
113
Chapter 14: Files
Reading from a Text File
• A partial list of BufferedReader methods:
Description
Action
int read()
Reads a character, returning it in
int form.
int read(char[] cbuf, Reads up to len characters of data
int off,
into the array cbuf, starting at the
int len)
position indicated by off. Returns
the number of characters read.
String readLine()
Reads a single line of characters and
returns it.
• All three methods throw IOException if an error occurs.
• If one of the read methods fails to read any input because
it reaches the end of the file, it returns –1.
Java Programming
FROM THE BEGINNING
114
Chapter 14: Files
Reading from a Text File
• The first version of the read method reads one
character from a file.
• read returns an integer, so a cast is necessary
before using the return value as a character.
• A loop that reads all the characters in a file:
while (true) {
int charValue = in.read();
if (charValue == -1)
break; // End of file reached
char inputChar = (char) charValue;
…
}
Java Programming
FROM THE BEGINNING
115
Chapter 14: Files
Reading from a Text File
• The readLine method reads characters until it
encounters a line feed ('\n'), a carriage return
('\r'), or a carriage return followed immediately
by a line feed.
• readLine returns a string containing all the
characters it read, not including the line-feed
and/or carriage-return character.
• readLine returns null if it was unable to read
any characters at all because it reached the end of
the input file.
Java Programming
FROM THE BEGINNING
116
Chapter 14: Files
Reading from a Text File
• A loop that uses readLine to read all the lines in
a file:
while (true) {
String line = in.readLine();
if (line == null)
break;
…
}
Java Programming
FROM THE BEGINNING
117
Chapter 14: Files
Program: Converting Text to HTML
• The ConvertToHTML program converts an
ordinary text file into an HTML file.
• An HTML (Hypertext Markup Language) file is a
text file that contains formatting commands,
known as tags.
• These commands are used by a browser to format
the file for display.
Java Programming
FROM THE BEGINNING
118
Chapter 14: Files
A Sample Text File
Java Programming
FROM THE BEGINNING
119
Chapter 14: Files
Running the ConvertToHTML Program
• The ConvertToHTML program expects the name
of a text file to be specified on the command line:
java ConvertToHTML norton.txt
• The program will create a file with the same name,
but with the extension .html.
Java Programming
FROM THE BEGINNING
120
Chapter 14: Files
Java Programming
FROM THE BEGINNING
121
Chapter 14: Files
Viewing norton.html in a Browser
Java Programming
FROM THE BEGINNING
122
Chapter 14: Files
Program Behavior
• The ConvertToHTML program will use the first line
in the original file as the text for both the <TITLE>
and <H2> tags.
• Each blank line will be replaced by the line
<P>
• Nonblank lines after the first one are copied to the
HTML file without change.
• Certain characters have a special meaning in HTML,
including &, <, and >. The program should (but does
not) replace these characters by special codes if they
appear in the original file.
Java Programming
FROM THE BEGINNING
123
Chapter 14: Files
ConvertToHTML.java
// Converts an ordinary text file to an HTML file
import java.io.*;
public class ConvertToHTML {
public static void main(String[] args) {
// Terminate program if number of command-line arguments
// is wrong
if (args.length != 1) {
System.out.println("Usage: java ConvertToHTML file");
System.exit(-1);
}
Java Programming
FROM THE BEGINNING
124
Chapter 14: Files
// Call the generateHTMLFile method, which converts the
// original file to an HTML file. Terminate the program
// if an exception occurs.
try {
generateHTMLFile(args[0]);
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
System.exit(-1);
}
}
// Returns a file name that is identical to fileName, but
// with the extension changed to .html
private static String createHTMLFileName(String fileName) {
int index = fileName.lastIndexOf(".");
if (index != -1)
fileName = fileName.substring(0, index);
return fileName + ".html";
}
Java Programming
FROM THE BEGINNING
125
Chapter 14: Files
// Generates an HTML file containing the contents of the
// original file, with HTML tags added
private static void generateHTMLFile(String originalFile)
throws IOException {
// Open the original file for reading
FileReader fileIn = new FileReader(originalFile);
BufferedReader in = new BufferedReader(fileIn);
// Determine the name of the HTML file by changing the
// extension of the original file name to .html
String newFile = createHTMLFileName(originalFile);
// Open the HTML file for writing
FileWriter fileOut = new FileWriter(newFile);
BufferedWriter bufOut = new BufferedWriter(fileOut);
PrintWriter out = new PrintWriter(bufOut);
Java Programming
FROM THE BEGINNING
126
Chapter 14: Files
// Read the first line of the original file. Terminate
// the program if the original file is empty.
String firstLine = in.readLine();
if (firstLine == null) {
System.out.println("File is empty");
System.exit(-1);
}
// Write a series of tags to the HTML file, using the
// first line of the original file for the <TITLE> and
// <H2> tags.
out.println("<HTML>");
out.println("<HEAD>");
out.println("<TITLE>" + firstLine + "</TITLE>");
out.println("</HEAD>");
out.println("<BODY>");
out.println("<H2>" + firstLine + "</H2>");
Java Programming
FROM THE BEGINNING
127
Chapter 14: Files
// Copy the remaining lines of the original file to the
// HTML file, replacing each empty line with a <P> tag
while (true) {
String currentLine = in.readLine();
if (currentLine == null)
break;
if (currentLine.length() == 0)
out.println("<P>");
else
out.println(currentLine);
}
// Write the closing tags to the HTML file
out.println("</BODY>");
out.println("</HTML>");
}
}
// Close both files
in.close();
out.close();
Java Programming
FROM THE BEGINNING
128
Chapter 14: Files
14.7 Reading and Writing Objects
• Objects can be written to a file and later read back
in.
• A file that contains objects is always a binary file.
• Writing an object to a file involves saving the
values of all the object’s instance variables.
• In addition, a “tag” will need to be saved to
indicate the object’s type.
• If any of the values stored in an object are
references to other objects, those objects will need
to be saved as well.
Java Programming
FROM THE BEGINNING
129
Chapter 14: Files
Serialization
• When objects are written to a file, Java uses a
process known as serialization.
• Java automatically adds information to each object
to identify its class.
• If the object contains references to other objects,
those objects are stored as well.
• Each object is stored only once, regardless of the
number of references to it.
Java Programming
FROM THE BEGINNING
130
Chapter 14: Files
The Serializable Interface
• The Serializable interface is used to indicate
that a class is serializable.
• Serializable belongs to the java.io
package.
• A number of classes in the Java API implement
the Serializable interface.
• If a class is serializable, then all its subclasses are
as well.
Java Programming
FROM THE BEGINNING
131
Chapter 14: Files
The Serializable Interface
• To make a class serializable, the words
implements Serializable are added to its
declaration:
class MyClass implements Serializable {
…
}
• Serializable is empty, so MyClass doesn’t
need to contain any particular methods.
Java Programming
FROM THE BEGINNING
132
Chapter 14: Files
The Serializable Interface
• Two other conditions are required in order for a
class to be serializable:
– If any of the instance variables in the class contain
objects, these objects must belong to serializable
classes.
– The class’s direct superclass must have a no-arg
constructor or be serializable.
• If a program tries to write an object that’s not
serializable, a NotSerializableException
will occur.
Java Programming
FROM THE BEGINNING
133
Chapter 14: Files
Writing Objects
• In order to write objects to a file, an instance of the
ObjectOutputStream class is needed.
• This instance will be layered on top of an instance of
the FileOutputStream class:
FileOutputStream fileOut =
new FileOutputStream(fileName);
ObjectOutputStream out =
new ObjectOutputStream(fileOut);
• The argument to the ObjectOutputStream
constructor can be any kind of output stream.
• The constructor may throw IOException.
Java Programming
FROM THE BEGINNING
134
Chapter 14: Files
Writing Objects
• The most important ObjectOutputStream
method is writeObject, which is used to write
an object to a stream.
• The parameter to writeObject has type
Object, so any object can be passed to
writeObject.
• The String class implements the
Serializable interface, so a string can be
passed to writeObject:
out.writeObject("Testing...");
Java Programming
FROM THE BEGINNING
135
Chapter 14: Files
Writing Objects
• Exceptions that can arise as a result of calling
writeObject:
– IOException
– InvalidClassException
– NotSerializableException
• InvalidClassException and
NotSerializableException are indirect
subclasses of IOException, so a catch block
for IOException will handle those as well.
Java Programming
FROM THE BEGINNING
136
Chapter 14: Files
Writing Objects
• The remaining ObjectOutputStream
methods closely resemble DataOutputStream
methods.
• These methods are used to write other types of
data, such as integers, floating-point numbers, and
characters.
• By providing these methods, the
ObjectOutputStream class allows a file to
contain a mixture of objects and values of the
primitive types.
Java Programming
FROM THE BEGINNING
137
Chapter 14: Files
Reading Objects
• Before objects can be read, an instance of the
ObjectInputStream class must be created:
FileInputStream fileIn =
new FileInputStream(fileName);
ObjectInputStream in =
new ObjectInputStream(fileIn);
• The argument to the ObjectInputStream
constructor can be any kind of input stream.
Java Programming
FROM THE BEGINNING
138
Chapter 14: Files
Reading Objects
• The ObjectInputStream constructor may throw
IOException and StreamCorruptedException (the format of the underlying file is
wrong).
• A catch block for IOException can handle both
exceptions.
• Objects are read from an ObjectInputStream by
calling the readObject method.
• readObject returns an Object value, which can
then be cast to the proper type:
String str = (String) in.readObject();
Java Programming
FROM THE BEGINNING
139
Chapter 14: Files
Reading Objects
• Exceptions that can arise as a result of calling
readObject:
– ClassNotFoundException—The Java interpreter is
unable to locate the class to which the object belongs.
– InvalidClassException—There’s a problem with
the class to which the object belongs.
– IOException—The underlying stream has a problem.
– OptionalDataException—The readObject
method encountered unexpected data.
– StreamCorruptedException—The readObject
method encountered an inconsistency in the data.
Java Programming
FROM THE BEGINNING
140
Chapter 14: Files
Reading Objects
• A catch block for IOException will also
handle InvalidClassException,
OptionalDataException, and
StreamCorruptedException.
• ClassNotFoundException is not a subclass
of IOException, however, so it will need a
separate catch block.
Java Programming
FROM THE BEGINNING
141
Chapter 14: Files
Reading Objects
• The remaining ObjectInputStream methods
are used to read other types of data, such as
integers, floating-point numbers, and characters.
• These methods closely resemble
DataInputStream methods.
Java Programming
FROM THE BEGINNING
142
Chapter 14: Files
Reading and Writing
Entire Data Structures
• Data structures are objects, so they can be written to a file
with a single method call.
• An example of writing an array to a file:
int[] a = {1, 2, 3};
try {
FileOutputStream fileOut =
new FileOutputStream(fileName);
ObjectOutputStream out =
new ObjectOutputStream(fileOut);
out.writeObject(a);
out.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
Java Programming
FROM THE BEGINNING
143
Chapter 14: Files
Reading and Writing
Entire Data Structures
• Code that reads the array back in:
int[] a;
try {
FileInputStream fileIn =
new FileInputStream(fileName);
ObjectInputStream in =
new ObjectInputStream(fileIn);
a = (int[]) in.readObject();
in.close();
} catch (IOException e) {
System.out.println(e.getMessage());
} catch (ClassNotFoundException e) {
System.out.println(e.getMessage());
}
Java Programming
FROM THE BEGINNING
144
Chapter 14: Files
Reading and Writing
Entire Data Structures
• Similar code can be used to write a vector or other
data structure and then read it later.
• When serializing a data structure, make sure that
the elements of the data structure are serializable.
• Otherwise, a NotSerializableException
will occur when the program is executed.
Java Programming
FROM THE BEGINNING
145
Chapter 14: Files
14.8 Case Study:
A Phone Directory (Revisited)
• The original PhoneDirectory program
(Section 5.8) allowed the user to enter names and
numbers as well as look up existing names.
• Unfortunately, the names and phone numbers were
lost when the program terminates.
• The new version of PhoneDirectory will save
the names and numbers in a file when it
terminates.
• When the program is run the next time, it restores
the names and numbers by reading from the file.
Java Programming
FROM THE BEGINNING
146
Chapter 14: Files
Changes to the PhoneDirectory Program
• Other differences between the old and new
versions of PhoneDirectory:
– PhoneRecord objects will be stored in a vector rather
than an array.
– The new program relies on helper methods instead of a
single main method.
• Helper methods:
–
–
–
–
addNumber—Implements the a (add) command
findNumber—Implements the f (find) command
saveRecords—Saves records in a file
readRecords—Reads records from the same file
Java Programming
FROM THE BEGINNING
147
Chapter 14: Files
Changes to the PhoneDirectory Program
• saveRecords will save the vector of records in
a file named records.dat.
• If readRecords is unable to read from the
records.dat file (or the file doesn’t exist), the
method will display a message and create an
empty vector.
• The PhoneRecord class is the same as before,
except that implements Serializable will
be added to the class declaration.
Java Programming
FROM THE BEGINNING
148
Chapter 14: Files
PhoneDirectory2.java
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
Program name: PhoneDirectory2
Author: K. N. King
Written: 1999-12-22
Stores names and telephone numbers and allows phone
numbers to be looked up. The user is given a menu of
three commands:
a - Add a new phone number
f - Find a phone number
q - Quit
The "a" command prompts the user to enter a name and a
number, which are then stored in the program's database.
Java Programming
FROM THE BEGINNING
149
Chapter 14: Files
//
//
//
//
//
//
//
//
//
//
//
//
The "f" command prompts the user to enter a name; the
program then displays all matching names in the database,
along with the corresponding phone numbers. It is not
necessary to enter the entire name; all names that begin
with the specified characters will be displayed. The "f"
command ignores the case of letters when looking for
matching names.
The
and
the
and
"q" command causes the program to terminate. The names
numbers are saved in a file named "records.dat". When
program is run the next time, it will open the file
read the records.
import java.io.*;
import java.util.*;
import jpb.*;
Java Programming
FROM THE BEGINNING
150
Chapter 14: Files
public class PhoneDirectory2 {
// Class variables
private static final String DATA_FILE = "records.dat";
private static Vector records;
public static void main(String[] args) {
// Read records from data file
readRecords();
// Display list of commands
System.out.println("Phone directory commands:\n" +
" a - Add a new phone number\n" +
" f - Find a phone number\n" +
" q - Quit\n");
Java Programming
FROM THE BEGINNING
151
Chapter 14: Files
// Read and execute commands
while (true) {
// Prompt user to enter a command
SimpleIO.prompt("Enter command (a, f, or q): ");
String command = SimpleIO.readLine().trim();
// Determine whether command is "a", "f", "q", or
// illegal; execute command if legal.
if (command.equalsIgnoreCase("a")) {
// Command is "a". Call addNumber to add a new
// name and number to the database
addNumber();
} else if (command.equalsIgnoreCase("f")) {
// Command is "f". Call findNumber to find phone
// numbers that match the user's criteria.
findNumber();
Java Programming
FROM THE BEGINNING
152
Chapter 14: Files
} else if (command.equalsIgnoreCase("q")) {
// Command is "q". Save records in data file and
// terminate program.
saveRecords();
return;
} else {
// Command is illegal. Display error message.
System.out.println("Command was not recognized; " +
"please enter only a, f, or q.");
}
System.out.println();
}
}
Java Programming
FROM THE BEGINNING
153
Chapter 14: Files
///////////////////////////////////////////////////////////
// NAME:
addNumber
// BEHAVIOR:
Prompts the user for a name and number,
//
then creates a phone record and stores it in
//
the records vector.
// PARAMETERS: None
// RETURNS:
Nothing
///////////////////////////////////////////////////////////
private static void addNumber() {
SimpleIO.prompt("Enter new name: ");
String name = SimpleIO.readLine().trim();
SimpleIO.prompt("Enter new phone number: ");
String number = SimpleIO.readLine().trim();
records.addElement(new PhoneRecord(name, number));
}
Java Programming
FROM THE BEGINNING
154
Chapter 14: Files
///////////////////////////////////////////////////////////
// NAME:
findNumber
// BEHAVIOR:
Prompts the user for a search key. Searches
//
the records vector for records whose names
//
begin with the search key. Prints these
//
names and the corresponding phone numbers.
// PARAMETERS: None
// RETURNS:
Nothing
///////////////////////////////////////////////////////////
private static void findNumber() {
SimpleIO.prompt("Enter name to look up: ");
String key = SimpleIO.readLine().trim().toLowerCase();
for (int i = 0; i < records.size(); i++) {
PhoneRecord currentRecord =
(PhoneRecord) records.elementAt(i);
String name = currentRecord.getName().toLowerCase();
if (name.startsWith(key))
System.out.println(currentRecord.getName() + " " +
currentRecord.getNumber());
}
}
Java Programming
FROM THE BEGINNING
155
Chapter 14: Files
///////////////////////////////////////////////////////////
// NAME:
readRecords
// BEHAVIOR:
Restores the records vector to its previous
//
state by reading it (as a single object)
//
from the data file. Creates an empty vector
//
if the file does not exist or cannot be
//
read.
// PARAMETERS: None
// RETURNS:
Nothing
///////////////////////////////////////////////////////////
private static void readRecords() {
try {
FileInputStream fileIn = new FileInputStream(DATA_FILE);
ObjectInputStream in = new ObjectInputStream(fileIn);
records = (Vector) in.readObject();
in.close();
} catch (Exception e) {
System.out.println(DATA_FILE + " does not exist or " +
"cannot be read\n");
records = new Vector();
}
}
Java Programming
FROM THE BEGINNING
156
Chapter 14: Files
///////////////////////////////////////////////////////////
// NAME:
saveRecords
// BEHAVIOR:
Saves the records vector (as a single
//
object) by writing it to the data file.
// PARAMETERS: None
// RETURNS:
Nothing
///////////////////////////////////////////////////////////
private static void saveRecords() {
try {
FileOutputStream fileOut =
new FileOutputStream(DATA_FILE);
ObjectOutputStream out =
new ObjectOutputStream(fileOut);
out.writeObject(records);
out.close();
} catch (IOException e) {
System.out.println("Error writing to " + DATA_FILE);
}
}
}
Java Programming
FROM THE BEGINNING
157
Chapter 14: Files
// Represents a record containing a name and a phone number
class PhoneRecord implements Serializable {
private String name;
private String number;
///////////////////////////////////////////////////////////
// NAME:
PhoneRecord
// BEHAVIOR:
Constructs a phone record containing the
//
specified name and phone number
// PARAMETERS: personName - name of a person
//
phoneNumber - phone number for that person
///////////////////////////////////////////////////////////
public PhoneRecord(String personName, String phoneNumber) {
name = personName;
number = phoneNumber;
}
Java Programming
FROM THE BEGINNING
158
Chapter 14: Files
///////////////////////////////////////////////////////////
// NAME:
getName
// BEHAVIOR:
Returns the name stored in this record
// PARAMETERS: None
// RETURNS:
The name stored in this record
///////////////////////////////////////////////////////////
public String getName() {
return name;
}
///////////////////////////////////////////////////////////
// NAME:
getNumber
// BEHAVIOR:
Returns the phone number stored in this
//
record
// PARAMETERS: None
// RETURNS:
The phone number stored in this record
///////////////////////////////////////////////////////////
public String getNumber() {
return number;
}
}
Java Programming
FROM THE BEGINNING
159