Chapter 14 - Files, Streams, and Input/Output Techniques
|
Chapter Objectives:
-
Be able to read and write text files.
-
Know how to read and write binary files.
-
Understand the use of InputStreams and OutputStreams
-
Be able to design methods for performing input and output.
-
Know how to use the File class.
-
Be able to use the JFileChooser class.
|
Index:
|
Introduction
-
Input refers to reading data from some external source into a running program.
-
Output refers to writing data from a running program to some external destination.
-
A file is a collection of data stored on a disk or CD or some other storage
medium.
-
Files and their data persist beyond the duration of the program.
Streams and Files
-
A stream is an object that delivers information to and from another object.
-
All I/O in Java is based on streams.
-
An input stream starts with an input device (e.g. existing file,
modem, etc.) and travels as a continuos series of bytes to a program.
-
An output stream starts with a program sending a series of bytes
to an output device (e.g. data file, modem, etc.).
-
Data for a particular system is often organized in a hierachy
-
Database - collection of files
-
File - collection of records
-
Record - collection of fields
-
Field - one or more bytes
-
Byte - 8 bits
Binary Files versus Text Files
-
A binary file is processed as a sequence of bytes, whereas a text file
is processed as a sequence of characters. Both types store data as a sequence
of bits and bytes (0’s and 1’s).
-
Text files are portable because they are based on the ASCII code.
-
Binary files are not portable because they use different representations
of binary data.
-
IS programs typically deal with textual files. This is due to the fact
that text files is the easiest way to enter data (using notepad) or to
import/export data with programs like MS Excel and MS Access. This is the
type of file we will address in this class.
-
Java binaries are platform independent because Java defines the sizes of
binary data.
-
In other systems, the number of bytes used to store data differ, for example,
in ASCII systems, 1 byte is used to store each character, while under UniCode
it is 2 bytes. Some MS Windows programs use integers that are two bytes
long and some 4 bytes long. Thus a data file created by one system
could not easily be read by another.
-
Subclasses of DataInputStreams and DataOutputStreams are used for binary
I/O.
-
Subclasses of Reader and Writer are normally used for text I/O.
-
Example: PrintWriter has methods for printing all types of data.
-
public void print(int i); public void println(int i);
-
public void print(long l); public void println(long l);
-
public void print(float f); public void println(float f);
-
public void print(double d); public void println(double d);
-
public void print(String s); public void println(String s);
-
public void print(Object o); public void println(Object o);
-
Note :
-
the "print" methods write the data to the stream, whereas println writes
the data followed by an end of line character.
-
this is a good example of polymorphism.
Class |
Description |
InputStream |
Abstract root class of all binary input streams |
File |
Provides platform independent methods for dealing with files and directories |
FileInputStream |
Provides methods for reading bytes from a binary file |
BufferedInputStream |
Provides input data buffering for reading large files |
DataInputStream |
Provides methods for reading Java's primitive data types |
OutputStream |
Abstract root class of all binary output streams |
FileOutputStream |
Provides methods for writing bytes to a binary file |
BufferedOutputStream |
Provides output data buffering for writing large files |
DataOutputStream |
Provides methods for writing Java's primitive data types |
Reader |
Abstract root class for all text input streams |
BufferedReader |
Provides buffering for character input streams |
FileReader |
Provides methods for character input on files |
StringReader |
Provides input operations on Strings |
Writer |
Abstract root class for all text output streams |
BufferedWriter |
Provides buffering for character output streams |
FileWriter |
Provides methods for output to text files |
PrintWriter |
Provides methods for printing binary data as characters |
StringWriter |
Provides output operations to Strings |
Table 14-1 Important Stream Classes
Buffering and Filtering
-
Different filters which can help transform the bytes as they enter and
leave your program via streams
-
Filter types and their associated classes:
-
Byte streams - data is a series of bytes that can be read/written, the
bytes are read and written. (FileInputStream,FileOutputStream)
-
Data streams - data is a series of values that can be of type boolean,
byte, double, int, long, and short. (DataInputStream,DataOutputStream)
-
Character streams - data is a series of characters. (FileReader, FileWriter)
-
Streams can also be "buffered", these types of streams cache the data in
memory for efficiency.
-
A buffer is a relatively large region of memory used to temporarily store
data during I/O.
-
BufferedInputStream and BufferedOutputStream are designed for this purpose.
-
The StringReader and StringWriter classes provide methods for treating
Strings and StringBuffers as I/O streams.
Text based data files
-
Data files can take on any format the the programmer decides on.
If the programmer is sane, then he/she will either use a delimited file
or a fixed field file. Both of these types can be easily read into/outof
MS Excel and MS Access.
-
Delimited files - use a special character such as a tab between
each field. the fields can then be as long or as short as necessary. You
can use the StringTokenizer
object to help parse the lines.
-
Fixed width field files - predesignate which characters on
a line go to what field. If the field is too long to fit into the
designated space, then the data is lopped off. If it is shorter than the
designated space, then spaces are appended. You can use the subString method
of the String object to parse lines in this type of file.
-
Under this method a program reads/writes the data files a line at a time.
After each line is read, then the program must separate the line into its
component fields (parse). For example, a customer file might have a separate
line for each customer, on that line would appear the customer's name,
address, city, state, etc. Numeric fields read in as strings would have
to be converted to numbers using Integer.parseInt()
and the Float.parseFloat
methods (be sure to catch the NumberFormatException).
-
To perform this in Java it is best to associate one data object with the
file (e.g. CustomerList) and another with each record (e.g. Customer).
The file object reads the file a line at a time, then passes it to the
record object to parse into its fields and store it in its attributes.
Example Customer file, using fixed width fields
-
To read data from a text file you must do the following:
-
Create a FileReader
(input stream) object to read the file
-
Convert the FileReader to a BufferedReader
object
-
you could also use the LineNumberReader
object, this does the same thing, and keeps track of the line number read
from the file for you.
-
Read the data lines using one of BufferedReader's methods (e.g. readLine),
when a null is returned you have hit the end of the file.
-
Close the file
-
Example code:
try{
String line;
// declare a string object to read data into
FileReader file = new FileReader(filename);
// create a file reader stream, filename is a string
BufferedReader bReader = new BufferedReader(file);
// convert it to a buffered reader so we can use readLine()
boolean eof = false;
// use this to watch for the end of file
while(!eof){
// while not at the end of the file
line = bReader.readLine();
// try to read one line of text
if(line == null)
// end of file reached ??
eof= true;
// then exit while loop
else
System.out.println(line);
// do something with the line, for now just print to the DOS window
}
bReader.close();
// close the file (also closes the stream)
}
catch(IOException e){
System.out.println("IE Exception
when loading productlist from [" + filename + "] error: " + e.getMessage());
}
Text based report files
-
Text based report files generally take on one of three formats:
-
Text with line breaks - this is the simplest format, readable by any program,
but does not allow you to have headings, tables, font changes, etc.
-
HTML - becoming very prevalent since everyone has a web browser to view
them and programs like MS word can read them as well. They are relatively
easy to create and allow formatting. They are also platform independent.
-
RTF - rich text files. This format was invented by Microsoft so that documents
could be shared between platforms and between word processor more easily
(than .DOC files). They are a bit more difficult to create and may not
be as portable as HTML since the standard is very "loose", i.e. not all
word processors recognize all the RTF formatting tags.
-
To write data to a text file you must do the following:
-
Create a FileWriter
(output stream) object to write the file
-
Convert the FileWriter to a PrintWriter
object
-
you could also use the BufferedWriter
object, this object takes a little more coding since it does not have a
println method
-
Write the data lines using one of PrintWriters methods (e.g. println)
-
Close the file
-
Example:
try{
FileWriter file = new FileWriter("test.txt");
// create a file writer stream
PrintWriter pWriter = new PrintWriter(file);
// convert it to a PrintWriter so we can use all the print and println
String fred = "Fred Flinstone";
// declare and initialize a string variable
int age = 33; // declare and initilize
an integer variable
float salary = 32000.01F; // and
a float variable
pWriter.print("Hello, my name is ");
pWriter.println(fred);
pWriter.print("I earn ");
pWriter.print(salary);
pWriter.println(" rocks a year");
pWriter.print("I am only ");
pWriter.print(age);
pWriter.println(" years old.");
pWriter.close();
}
catch(IOException e){
System.out.println("oops");
}
-
Produces the following output:
Hello, my name is Fred Flinstone
I earn 32000.01 rocks a year
I am only 33 years old.
-
Note : The DecimalFormat object
could have been used to format the salary
File Class
-
A path is a description of a file's location in its hierarchy.
-
Absolute path name, complete path specification starting from
the root of the file system:
-
/root/java/example/MyClass.java
-
Relative path name, specified in relation to the current
directory:
-
In the previous example, if the file did not exist or the user did not
have proper access priviledges (read/write), then an IOException would
have resulted. To avoid this, the File
class can be used.
-
Some useful methods provided by the File class
public boolean canRead();
// Is the file readable?
public boolean canWrite();
// Is the file writeable?
public boolean delete();
// Delete the file
public boolean exists();
// Does the file exist?
public String getParent();
// Get the file or directory's parent
public String getPath();
// Get the file's path
public boolean isDirectory();
// Is the file a directory ?
public boolean isFile();
// Is the file a file ?
public long lastModified();
// When was the file last modified?
public long length();
// How many bytes does it contain?
public String[] list();
// List the contents of this directory
public boolean renameTo(File
f); // Rename this file to f's name
-
Example, the following determines if a file is readable or not.
private boolean isReadableFile(String fileName) {
try {
File file = new
File(fileName);
if (!file.exists())
throw (new FileNotFoundException("No such File:" + fileName));
if (!file.canRead())
throw (new IOException("File not readable: " + fileName));
return true;
} catch (FileNotFoundException e) {
System.out.println("IOERROR:
File NOT Found: " + fileName + "\n");
return false;
} catch (IOException e) {
System.out.println("IOERROR:
" + e.getMessage() + "\n");
return false;
}
} // isReadableFile
Command Line Arguments
-
Command line arguments are strings separated by spaces that follow the
program name on the command line.
-
Under MS Windows the command line can be typed into a DOS box or into the
Run command under the start menu.
-
In a command-line interface arguments specified on the command line are
input to the main() method as an array of strings, each item in the array
has one argument.
-
They are an alternative to using a GUI environment (FileDialog or JFileChooser).
Most MS Windows programs will accept input both GUI and command line inputs.
-
Example:
public static void main(String args[]) {
FileCopy fc = new FileCopy();
if (args.length >= 2)
fc.fileCopy(args[0], args[1]);
else {
System.out.println("Usage:
java FileCopy srcFile destFile");
System.exit(1);
}
} // main()
Reading and Writing Objects
-
To read or write an entire object (as opposed to a single attribute) requires
you to implement procedures within that object that can turn the object
into a stream of bytes (for output) and convert a stream of bytes back
into the object (on input)
-
Object serialization is the process of writing an object as a series
of bytes.
-
Deserialization is the opposite (input) process.
-
ObjectOutputStream
- can be used to serialize objects
-
ObjectInputStream
- can be used to deserialize objects
-
Steps needed to make an object serializable:
-
The object should implement the Serializable
class (no need to add extra method)
-
All its data members should be serializable or declared as transient.
-
if an attribute is another object, then that object must be serializable
-
attributes of type int, float, etc. are already serializable
-
The object should provide routines for reading and writing
-
e.g. writeToFile, and readFrom File (these could take on any name)
JFileChooser
To use the JFileChooser
object to prompt the user for a file name you must:
Advanced example:
-
This example reads in a tab delimited text file that contains student first
names, last names, major, credits earned, and gpa. It has a function that
formats a report in HTML format using an HTMLPrinter object created for
that purpose.
-
Input data can be specified on the command line (java IOSample studentdata.txt)
or opened via a menu item that uses JFileChooser
-
The example consists of three classes:
Other Notes:
-
Some Java Objects, for example JTextArea provide their own methods for
writing to a file. All you need to do is to open a stream of the appropriate
type and pass it to the method. this was done in the TextEditor
example presented in chapter 9.
-
You should use the File.separator constant when defining paths, not all
systems use a '\' character. MS Windows likes both '\' and '/' characters,
but Unix does not!
Summary:
Keywords: absolute path name, buffering, buffer, binary file,
command-line argument, database, data hierarchy, directory, end-of-file
character, field, file, filtering,input stream, output stream, path, platform
independent, record,relative path name, serialization, stream, text file,
UTF
Suggested Excercises: 1, 2, 3, 4, 7, 8, 12, 15, 17, 18