Reading
and Writing Files
Java provides a number of
classes and methods that allow you to read and write files. Before we begin, it
is important to state that the topic of file I/O is quite large and file I/O is
examined in detail in Part II. The purpose of this section is to introduce the
basic techniques that read from and write to a file. Although bytes streams are
used, these techniques can be adapted to the character-based streams.
Two of the most often-used
stream classes are FileInputStream
and FileOutputStream, which create
byte streams linked to files. To open a file, you simply create an object of
one of these classes, specifying the name of the file as an argument to the
constructor. Although both classes support additional constructors, the
following are the forms that we will be using:
FileInputStream(String fileName) throws FileNotFoundException
FileOutputStream(String fileName)
throws FileNotFoundException
Here, fileName specifies the name of the file that you want to open. When
you create an input stream, if the file does not exist, then FileNotFoundException is thrown. For
output streams, if the file cannot be opened or created, then FileNotFoundException is thrown. FileNotFoundException is a subclass of IOException. When an output file is
opened, any preexisting file by the
same name is destroyed.
When you are done with a
file, you must close it. This is done by calling the close( ) method, which is implemented by both FileInputStream and FileOutputStream.
It is shown here:
void close( ) throws
IOException
Closing a file releases the
system resources allocated to the file, allowing them to be used by another
file. Failure to close a file can result in “memory leaks” because of unused
resources remaining allocated.
Before moving on, it is
important to point out that there are two basic approaches that you can use to
close a file when you are done with it. The first is the traditional approach,
in which close( ) is called
explicitly when the file is no longer needed. This is the approach used by all
versions of Java prior to JDK 7 and is, therefore, found in all pre-JDK 7
legacy code. The second is to use the try-with-resources
statement added by JDK 7, which automatically closes a file when it is no
longer needed. In this approach, no explicit call to close( ) is executed. Since there is a large amount of pre-JDK 7
legacy code that is still being used and maintained, it is important that you
know and understand the traditional approach. Therefore, we will begin with it.
The new automated approach is described in the following section.
To read from a file, you can
use a version of read( ) that is
defined within FileInputStream. The
one that we will use is shown here:
int read( ) throws
IOException
Each time that it is called,
it reads a single byte from the file and returns the byte as an integer value. read( ) returns –1 when the end of the
file is encountered. It can throw an
IOException.
The following program uses read( ) to input and display the
contents of a file that contains ASCII text. The name of the file is specified
as a command-line argument.
/* Display a text file.
To use this program, specify the name of the file
that you want to see.
For example, to see a file called TEST.TXT, use
the following command line.
java ShowFile TEST.TXT
*/
import java.io.*;
class ShowFile {
public static void main(String args[])
{
int i; FileInputStream fin;
First, confirm that a filename has been
specified.
if(args.length != 1) {
System.out.println("Usage: ShowFile
filename"); return;
}
Attempt to open the file.
try {
fin = new FileInputStream(args[0]);
} catch(FileNotFoundException e) {
System.out.println("Cannot Open
File"); return;
}
//At this point, the file is open and can be
read.
//The following reads characters until EOF is
encountered.
try {
do {
= fin.read();
if(i != -1) System.out.print((char) i);
} while(i != -1);
} catch(IOException e) {
System.out.println("Error Reading
File");
}
// Close the file.
try {
fin.close();
} catch(IOException e) {
System.out.println("Error Closing
File");
}
}
}
In the program, notice the try/catch blocks that handle the I/O
errors that might occur. Each I/O operation is monitored for exceptions, and if
an exception occurs, it is handled. Be aware that in simple programs or example
code, it is common to see I/O exceptions simply thrown out of main( ), as was done in the earlier
console I/O examples. Also, in some real-world code, it can be helpful to let
an exception propagate to a calling routine to let the caller know that an I/O
operation failed. However, most of the file
I/O examples in this book
handle all I/O exceptions explicitly, as shown, for the sake of illustration.
Although the preceding
example closes the file stream after the file is read, there is a variation
that is often useful. The variation is to call close( ) within a finally
block. In this approach, all of the methods that access the file are contained
within a try block, and the finally block is used to close the
file. This way, no matter how the try block
terminates, the file is closed.
Assuming the preceding example, here is how the try block that reads the file can be recoded:
try { do {
i = fin.read();
if(i != -1) System.out.print((char) i);
} while(i != -1);
} catch(IOException e) {
System.out.println("Error Reading
File");
} finally {
// Close file on the way out of the try block.
try {
fin.close();
} catch(IOException e) {
System.out.println("Error Closing
File");
}
}
Although not an issue in this
case, one advantage to this approach in general is that if the code that
accesses a file terminates because of some non-I/O related exception, the file
is still closed by the finally
block.
Sometimes it’s easier to wrap
the portions of a program that open the file and access the file within a
single try block (rather than
separating the two) and then use a finally
block to close the file. For example, here is another way to write the ShowFile program:
/* Display a text file.
To use this program, specify the name of the
file that you want to see.
For example, to see a file called TEST.TXT, use
the following command line.
java ShowFile TEST.TXT
This variation wraps the code that opens and
accesses the file within a single try block. The file is closed by the finally
block.
*/
import java.io.*;
class ShowFile {
public static void main(String args[])
{
int i;
FileInputStream fin = null;
First, confirm that a filename has been
specified.
if(args.length != 1) {
System.out.println("Usage: ShowFile
filename"); return;
}
//The following code opens a file, reads
characters until EOF is encountered, and then closes the file via a finally
block.
try {
fin = new FileInputStream(args[0]);
do {
i = fin.read();
if(i != -1) System.out.print((char) i);
} while(i != -1);
} catch(FileNotFoundException e) {
System.out.println("File Not Found.");
} catch(IOException e) {
System.out.println("An I/O Error Occurred");
} finally {
// Close file in all cases.
try {
if(fin != null) fin.close(); }
catch(IOException e) {
System.out.println("Error Closing
File");
}
}
}
}
In this approach, notice that
fin is initialized to null. Then, in the finally block, the file is closed only if fin is not null. This
works because fin will be non-null only if the file is successfully
opened. Thus, close( ) is not called
if an exception occurs while opening the file.
It is possible to make the try/catch sequence in the preceding
example a bit more compact. Because FileNotFoundException
is a subclass of IOException, it
need not be caught separately. For example, here is the sequence recoded to
eliminate catching FileNotFoundException.
In this case, the standard exception message, which describes the error, is displayed.
try {
fin = new FileInputStream(args[0]);
do {
i = fin.read();
if(i != -1) System.out.print((char) i);
} while(i != -1);
} catch(IOException e) {
System.out.println("I/O Error: " +
e);
} finally {
// Close file in all cases.
try {
if(fin != null) fin.close(); }
catch(IOException e) {
System.out.println("Error Closing
File");
}
}
In this approach, any error,
including an error opening the file, is simply handled by the single catch statement. Because of its
compactness, this approach is used by many of the I/O examples in this book. Be
aware, however, that this approach is not appropriate in cases in which you
want to deal separately with a failure to open a file, such as might be caused
if a user mistypes a filename. In such a situation, you might want to prompt
for the correct name, for example, before entering a try block that accesses the file.
To write to a file, you can
use the write( ) method defined by FileOutputStream. Its simplest form is
shown here:
void write(int byteval) throws IOException
This method writes the byte
specified by byteval to the file.
Although byteval is declared as an
integer, only the low-order eight bits are written to the file. If an error
occurs during writing, an IOException
is thrown. The next example uses write(
) to copy a file:
/* Copy a file.
To use this program, specify the name
of the source file and the destination file.
For example, to copy a file called FIRST.TXT to a file called SECOND.TXT, use
the following command line.
java CopyFile FIRST.TXT SECOND.TXT
*/
import java.io.*;
class CopyFile {
public static void main(String args[]) throws
IOException
{
int i;
FileInputStream fin = null; FileOutputStream
fout = null;
// First, confirm that both files have been
specified.
if(args.length != 2) {
System.out.println("Usage: CopyFile from
to"); return;
}
// Copy a File.
try {
// Attempt to open the files.
fin = new FileInputStream(args[0]);
fout = new FileOutputStream(args[1]);
do {
i = fin.read();
if(i != -1) fout.write(i);
} while(i != -1);
} catch(IOException e) {
System.out.println("I/O Error: " +
e);
} finally { try {
if(fin != null) fin.close(); }
catch(IOException e2) {
System.out.println("Error Closing Input
File");
}
try {
if(fout != null) fout.close();
} catch(IOException e2) {
System.out.println("Error Closing Output
File");
}
}
}
}
In the program, notice that
two separate try blocks are used
when closing the files. This ensures that both files are closed, even if the
call to fin.close( ) throws an
exception.
In general, notice that all
potential I/O errors are handled in the preceding two programs by the use of
exceptions. This differs from some computer languages that use error codes to
report file errors. Not only do exceptions make file handling cleaner, but they
also enable Java to easily differentiate the end-of-file condition from file
errors when input is being performed.
Related Topics
Privacy Policy, Terms and Conditions, DMCA Policy and Compliant
Copyright © 2018-2023 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.