Java programs read and write data by means of streams. A stream is a series of data elements that flows
from some input device to the program, or from the program to some output device. The general approach to
input and output (I/O) from a Java program is to:
Open the stream
While there is data to read or write
read and process data, or write data
}
Close the stream
The stream classes for I/O are grouped together in a Java package called java.io. A package is just a
collection of related classes. One can create packages of one’s own classes, but we will not be describing that
in this brief introduction to the language. The reason to mention the package name here is that a programmer
must import a package in order to take advantage of the classes within it. In order to use the stream classes
we will soon discuss, your program must have a statement at the very beginning, even before the class
statement, that says,
import java.io.*;
The asterisk means to import all the classes in the package. If the programmer wants only one of the
classes, the programmer can substitute the class name for the asterisk. Usually one simply types the line as we
have shown it.
The stream classes in Java are divided into two great categories: Reader/Writer and InputStream/
OutputStream. If the class is in the Reader/Writer category, it is a stream for reading and writing character
data—letters, numbers, and symbols. If the class is in the InputStream/OutputStream category, it
is a stream for reading and writing bytes—raw data, 8 bits at a time.
Students are sometimes confused thinking about the difference between character data and bytes. Are not
bytes used to encode characters? Yes they are. In fact, we could get along with just the InputStream/
OutputStream classes, and let programs be responsible for making sense of the data by converting the data to
characters when that was appropriate.
However, often data sources consist of character data, and it is very convenient to have I/O classes for
that common situation. If the information exists in the form of characters, a Reader/Writer will interpret
the information correctly and return a set of characters to the program. This saves the programmer having to
write a tedious conversion that would otherwise be necessary frequently.
If the information exists in some other form than characters, such as binary numbers in integer or floatingpoint
format, as in an image file, then it will not make sense to interpret the bit patterns as characters. In that
case, the programmer should use the InputStream/OutputStream classes, which will simply transfer the
bytes. Then the program will be responsible for interpreting the bytes correctly.
One other situation calls for the use of InputStream/OutputStream classes, too. That is when one
does not care what the data represent. This would be the case, for example, when the task is to copy a file. The
program doing the copying does not need to know what the content of the file means; it just needs to copy
each byte to a new file. In that case, using the InputStream/OutputStream classes instead of the
Reader/Writer classes makes sense, even if the file to be copied consists of characters, because the
InputStream/OutputStream classes will be more efficient—the step of translating bit patterns to characters
will be skipped.
There are 50 classes in java.io, and we will describe only a few here. To read a file of character data,
one would use a BufferedReader “wrapped around” a FileReader. The Java I/O design is very flexible,
and this is a good example of that. A FileReader reads characters from a file, and by wrapping the
FileReader with a BufferedReader, the I/O will be accomplished more efficiently by reading a group
of characters at once. The BufferedReader also provides a method called readLine(), which allows the
program to read a whole line at a time from a file into a String variable. Without the BufferedReader, a
FileReader only has methods to read characters.
Here is a little program to read a file of character data and display it on the screen:
import java.io.*;
/**
* A program that opens a character based file,
* specified on the command line,
* and shows its contents on standard output.
*
* @author Carl Reynolds
*/
public class ShowFile {
public static void main( String args[] ) {
BufferedReader in = null;
String line;
// Make sure the number of arguments is correct
if ( args.length != 1) {
System.err.println( "Usage: ShowFile sourceFile" );
System.exit(1);
}
// Attempt to open the file for reading
try {
in = new BufferedReader( new FileReader( args[0] ) );
}
catch ( FileNotFoundException e ) {
System.err.println( "ShowFile: " + e.getMessage() );
System.exit( 1 );
}
// Read and display
try {
while ( (line = in.readLine() ) != null ) {
System.out.println( line );
}
}
catch ( IOException e ) {
System.err.println( "ShowFile: " + e.getMessage() );
System.exit( 1 );
}
finally {
// Close the file
try{
in.close();
}
catch( Exception e ) {}
}
}//main
} //ShowFile
This program checks the command line arguments in the array of Strings called args to make sure that the
user provided a parameter for the file name. If the user provided exactly one argument, the program assumes this
argument is the name of a file, and it attempts to open the file using a BufferedReader inside a try block.
If all goes well, the program enters a while loop calling the readLine() method of the
BufferedReader to read a line of the file at a time into the String variable line, and then display the
text using the println() method. The loop will terminate when readLine() returns a null value; that is
the signal that the BufferedReader has encountered the end-of-file (EOF).
The program uses the finally block to close the file. Since the close() method can itself
throw an IOException, the call to close() within the finally block must also be surrounded by
a try block. If an error occurs here, however, this program simply ignores it; the catch block is empty
of any code.
Our second example reads a file for the simple purpose of copying the bits in the file to a new file. For this
purpose we use a BufferedInputStream wrapped around a FileInputStream. The program copies
the bits literally, one byte at a time. This approach is highly efficient because there is no overhead of translating
the bit patterns into characters.
import java.io.*;
/**
* Copy files from the command line.
* @author Paul Tymann
* @author Carl Reynolds
*/
public class FileCopy {
public static void main( String args[] ) {
BufferedInputStream in = null;
BufferedOutputStream out = null;
int data;
// Check command line arguments
if ( args.length != 2 ) {
System.out.println(
"Usage: FileCopy sourceFile destFile");
System.exit(1);
}
try {
// Open the input file.
in = new BufferedInputStream(
new FileInputStream( args[0]) );
// Open the output file.
// If the output file exists, it will be overwritten.
out = new BufferedOutputStream(
new FileOutputStream( args[1] ) );
}
catch ( FileNotFoundException e ) {
System.err.println("FileCopy: " + e.getMessage() );
System.exit( 1 );
}
// Now copy the files one byte at a time
try {
while ( (data = in.read() ) != -1) {
out.write( data );
}
}
catch ( IOException e ) {
System.err.println( "FileCopy: " + e.getMessage() );
System.exit( 1 );
}
finally {
// Close the files.
try {
in.close();
out.close();
}
catch( Exception e ) {}
}
}//main
} //FileCopy
When the program opens the BufferedOutputStream, the new FileOutputStream opens an
existing file for overwriting, or, if the output file does not exist, it creates a new output file for writing. There is a
second parameter in the constructor for the FileOutputStream which would allow a program to append to
an existing file, but we have not used that here.
With the read() method of the BufferedInputStream, either a byte of data is returned, or, if the
program encounters the EOF, a binary -1 is returned. As long as the read() continues to return bytes, the
program calls write() to copy the data. Though you see individual bytes being read and written, the transfer
is much more efficient than you might think, because the InputStream and OutputStream are buffered.
No comments:
Post a Comment