File Handling in Java
Streams
Stream: an object that either delivers data to its destination
(screen, file, etc.) or that takes data from a source (keyboard, file,
etc.)
it acts as a buffer between the data source and destination
Input stream: a stream that provides input to a program
System.in is an input stream
Output stream: a stream that accepts output from a program
System.out is an output stream
A stream connects a program to an I/O object
System.out connects a program to the screen
System.in connects a program to the keyboard
Binary and Text Files
All data and programs are ultimately just zeros and ones
each digit can have one of two values, hence binary
bit is one binary digit
byte is a group of eight bits
Text files: the bits represent printable characters
one byte per character for ASCII, the most common code
for example, Java source files are text files
any file created with a "text editor"
Binary files: the bits represent other types of encoded information,
such as executable instructions or numeric data
these files are easily read by the computer but not humans
they are not "printable" files
actually, you can print them, but they will be unintelligible
"printable" means "easily readable by humans when
printed"
Types of Streams
There are two types of streams
byte streams
character streams
Character Streams
Character streams create text files.
These are files designed to be read with a
text editor.
Java automatically converts its internal
unicode characters to the local machine
representation (ASCII in this case).
Byte Streams
Byte streams create binary files.
A binary file essentially contains the
memory image of the data. That is, it stores
bits as they are in memory.
Binary files are faster to read and write
because no translation need take place.
Binary files, however, cannot be read with a
text editor.
Classes
Java has 6 classes to support stream I/O
File: An object of this class is either a file
or a directory.
OutputStream: base class for byte output
streams
InputStream: base class for byte input
streams
Writer: base class for character output streams.
Reader: base class for character input streams.
RandomAccessFile: provides support for random
access to a file.
Note that the classes InputStream,
OutputStream, Reader, and Writer are abstract
classes.
Three stream objects are automatically created for
every application: System.in, System.out, and
System.err.
Subclasses – InputStream & OutputStream
BufferedInputStream • BufferedOutputStream
ByteArrayInputStream • ByteArrayOutputStream
DataInputStream • DataOutputStream
FileInputStream • FileOutputStream
FilterInputStream
• FilterOutputStream
LineNumberInputStream
• ObjectOutputStream
• PipedInputStream
ObjectInputStream • PipedOutputStream
PipedInputStream
PrintStream
PushbackInputStream
SequenceInputStream
StringBufferInputStream
Reading bytes of data
read() method of the InputStream class
reads a single unsigned byte of data and returns the int
value of the unsigned byte.
This is a number between 0 and 255.
If the end of stream is encountered it returns -1 instead,
and you can use this as a flag to watch for the end of
stream.
public abstract int read() throws IOException
11
How to do I/O
import java.io.*;
Open the stream
Use the stream (read, write, or both)
Close the stream
12
Buffered Streams
The java.io.BufferedInputStream and
java.io.BufferedOutputStream classes buffer reads and
writes by first storing the in a buffer (an internal array
of bytes).
Then the program reads bytes from the stream without
calling the underlying native method until the buffer is
empty.
The data is read from or written into the buffer in
blocks; subsequent accesses go straight to the buffer.
Readers and Writers
java.io.Reader and java.io.Writer classes are abstract
superclasses for classes that read and write character
based data.
The subclasses are notable for handling the conversion
between different character sets.
15
The Difference
Input and output streams are fundamentally byte based.
However readers and writers are based on characters,
which can have varying widths depending on the
character set being used.
For example, ASCII and ISO Latin-1 use one byte
characters. Unicode uses two byte characters. UTF-8
uses characters of varying width between one and three
bytes.
Readers and writers know how to handle all these
character sets and many more seamlessly.
java.io.Reader class
The methods of the java.io.Reader class are deliberately
similar to the methods of the java.io.InputStream class.
However rather than working with bytes, they work with
chars.
The basic read() method reads a single character (which
may may take between one and four bytes depending on
the character set) and returns the character as an int
between 0 and 65535.
It returns -1 if the end of stream is seen.
The java.io.Writer class
The methods of the java.io.Writer class are deliberately
similar to the methods of the java.io.OutputStream
class.
However rather than working with bytes, they work with
chars.
The basic write() method writes a single two-byte
character with a value between 0 and 65535.
The InputStreamReader Class
The java.io.InputStreamReader class serves as a bridge
between byte streams and character streams
It reads bytes from the input stream and translates them
into characters according to a specified character
encoding.
File Class
File class is a general machine independent interface to
the file system.
File class is not for the contents of a file, but the file
object
Directories are File Objects in java
Several methods are available with this class.
File Class Methods
getName()
getPath()
getAbsolutePath()
getParent()
isAbsolute()
lastModified()
IsFile()
isDirectory()
canRead()
canWrite()
Directory entries
String[] list()
File[] listFiles()
Both can use FileFilter interface
Boolean accept(File pathname)
File Streams
FileInputStream and FileOutputStream
Byte
Reads and writes data as sequence of Bytes
File Writers and Readers
• Char
– Reads and writes data as sequence Unicode
characters
Output to files
PrintStream: A class in the java.io package that
lets you print output to a file.
System.out is also a PrintStream.
Any methods you have used on System.out
(such as print, println) will work on every
PrintStream.
Printing into an output file, general syntax:
PrintStream <name> =
new PrintStream(new File("<file name>"));
If the given file does not exist, it is created.
If the given file already exists, it is overwritten.
Printing to files, example
Example:
PrintStream output = new PrintStream(new
File("output.txt"));
output.println("Hello, file!");
output.println("This is a second
line of output.");
similarly prompting for file name can be done.
25
open
use
Closing close
A stream is an expensive resource
There is a limit on the number of streams that you can
have open at one time
You should not have more than one stream open on
the same file
You must close a stream before you can open it again
Always close your streams!
26
Traditional way of Open-Close
File file = new File("input.txt");
InputStream is = null;
try {
is = new FileInputStream(file);
// do something with this input stream
// ...
}
catch (FileNotFoundException ex) {
System.err.println("Missing file " + file.getAbsolutePath());
}
finally {
if (is != null) {
is.close();
}
}
27
Try-with-resource (JDK7)
A “resources” implements the java.lang.AutoCloseable
interface. This resource would be automatically closed
and the end of the try block.
File file = new File("input.txt");
try (InputStream is = new FileInputStream(file)) {
// do something with this input stream
// ...
}
catch (FileNotFoundException ex) {
System.err.println("Missing file " +
file.getAbsolutePath());
}
28
Try-with-resource contd.
If both the (explicit) try block and the (implicit)
resource handling code throw an exception, then the try
block exception is the one which will be thrown.
The resource handling exception will be made available
via the Throwable.getSupressed() method of the thrown
exception.
29
Text File I/O
Important classes for text file output (to the file)
PrintWriter
FileOutputStream or FileWriter
Important classes for text file input (from the file):
BufferedReader
FileInputStream or FileReader
FileOutputStream and FileReader take file
names as arguments.
PrintWriter and BufferedReader provide
useful methods for easier writing and reading.
Usually need a combination of two classes
Buffering
Not buffered: each byte is read/written from/to disk as soon as
possible
“little” delay for each byte
A disk operation per byte---higher overhead
Buffered: reading/writing in “chunks”
Some delay for some bytes
Assume 16-byte buffers
Reading: access the first 4 bytes, need to wait for
all 16 bytes are read from disk to memory
Writing: save the first 4 bytes, need to wait for
all 16 bytes before writing from memory to disk
A disk operation per a buffer of bytes---lower overhead
Text File Output
To open a text file for output: connect a text file to a stream for writing
PrintWriter outputStream =
new PrintWriter(new
FileOutputStream("out.txt"));
Similar to the long way:
FileOutputStream s = new
FileOutputStream("out.txt");
PrintWriter outputStream = new PrintWriter(s);
Goal: create a PrintWriter object
which uses FileOutputStream to open a text file
FileOutputStream “connects” PrintWriter to a text file.
Output File Streams
PrintWriter FileOutputStream
Memory Disk
smileyOutStream smiley.txt
PrintWriter smileyOutStream = new PrintWriter( new FileOutputStream(“smiley.txt”) );
Methods for PrintWriter
Similar to methods for System.out.println
outputStream.println(count + " " + line);
print
format
flush: write buffered output to disk
close: close the PrintWriter stream (and file)
TextFileOutputDemo
Part 1
public static void main(String[] args)
{
PrintWriter outputStream = null;
try
{
outputStream = new PrintWriter(new
FileOutputStream("out.txt"));
}
catch(FileNotFoundException e)
{
System.out.println("Error opening the file
out.txt. “ + e.getMessage());
System.exit(0);
}
TextFileOutputDemo
Part 2
System.out.println("Enter three lines of text:");
String line = null;
int count;
for (count = 1; count <= 3; count++)
{
line = keyboard.nextLine();
outputStream.println(count + " " + line);
}
outputStream.close();
System.out.println("... written to out.txt.");
}
Overwriting a File
Opening an output file creates an empty file
Opening an output file creates a new file if it does not already
exist
Opening an output file that already exists eliminates the old file
and creates a new, empty one
data in the original file is lost
To see how to check for existence of a file, see the section of the
text that discusses the File class (later slides).
Appending to a Text File
To add/append to a file instead of replacing it, use a different constructor
for FileOutputStream:
outputStream =
new PrintWriter(new FileOutputStream("out.txt", true));
Second parameter: append to the end of the file if it exists?
Sample code for letting user tell whether to replace or append:
System.out.println("A for append or N for new file:");
char ans = keyboard.next().charAt(0);
true if user
boolean append = (ans == 'A' || ans == 'a');
enters 'A'
outputStream = new PrintWriter(
new FileOutputStream("out.txt", append));
Closing a File
An output file should be closed when you are done writing
to it (and an input file should be closed when you are done
reading from it).
Use the close method of the class PrintWriter
(BufferedReader also has a close method).
For example, to close the file opened in the previous
example:
outputStream.close();
If a program ends normally it will close any files that are
open.
Why Bother to Close a File?
If a program automatically closes files when it ends normally,
why close them with explicit calls to close?
Two reasons:
1. To make sure it is closed if a program ends abnormally (it
could get damaged if it is left open).
2. A file opened for writing must be closed before it can be
opened for reading.
Although Java does have a class that opens a file for
both reading and writing, it is not used in this text.
Text File Input
To open a text file for input: connect a text file to a stream for reading
Goal: a BufferedReader object,
which uses FileReader to open a text file
FileReader “connects” BufferedReader to the text file
For example:
BufferedReader smileyInStream =
new BufferedReader(new FileReader(“smiley.txt"));
Similarly, the long way:
FileReader s = new FileReader(“smiley.txt");
BufferedReader smileyInStream = new
BufferedReader(s);
Input File Streams
BufferedReader FileReader
Memory Disk
smileyInStream smiley.txt
BufferedReader smileyInStream = new BufferedReader( new FileReader(“smiley.txt”) );
Methods for BufferedReader
readLine: read a line into a String
no methods to read numbers directly, so
read numbers as Strings and then
convert them (StringTokenizer later)
read: read a char at a time
close: close BufferedReader
stream
Exception Handling with File I/O
Catching IOExceptions
IOException is a predefined class
File I/O might throw an IOException
catch the exception in a catch block that at least prints an error
message and ends the program
FileNotFoundException is derived from IOException
therefor any catch block that catches IOExceptions also
catches FileNotFoundExceptions
put the more specific one first (the derived one) so it catches
specifically file-not-found exceptions
then you will know that an I/O error is something other than
file-not-found
Example: public static void main(String[] args)
Reading a File {
String fileName = null; // outside try block, can be used in catch
Name from the try
{ Scanner keyboard = new Scanner(System.in);
Keyboard System.out.println("Enter file name:");
fileName = keyboard.next();
BufferedReader inputStream =
reading a file
new BufferedReader(new FileReader(fileName));
name from the String line = null;
keyboard line = inputStream.readLine();
System.out.println("The first line in " + filename + " is:");
using the file System.out.println(line);
name read from // . . . code for reading second line not shown here . . .
inputStream.close();
the keyboard } closing the file
catch(FileNotFoundException e)
reading data {
System.out.println("File " + filename + " not found.");
from the file }
catch(IOException e)
{
System.out.println("Error reading from file " + fileName);
}
}
Chapter 10 Java: an Introduction to Computer Science & Programming - Walter Savitch 45
Exception.getMessage()
try
{
…
}
catch (FileNotFoundException e)
{
System.out.println(filename + “ not
found”);
System.out.println(“Exception: “ +
e.getMessage());
System.exit(-1);
}
Testing for End of File in a Text File
When readLine tries to read beyond the end of a
text file it returns the special value null
so you can test for null to stop processing a
text file
read returns -1 when it tries to read beyond the
end of a text file
the int value of all ordinary characters is
nonnegative
Neither of these two methods (read and
readLine) will throw an EOFException.
Example: Using Null to
Test for End-of-File in a Text File
Excerpt from TextEOFDemo
int count = 0;
String line = inputStream.readLine();
while (line != null)
{
count++;
outputStream.println(count + " " + line);
line = inputStream.readLine();
}
Chapter 9 Java: an Introduction to Computer Science & Programming - Walter Savitch 48
Reading a file
try
{
ObjectInputStream inputStream =
new ObjectInputStream(new FileInputStream("numbers.dat"));
int n;
System.out.println("Reading ALL the integers");
System.out.println("in the file numbers.dat.");
try
{
while (true)
{
n = inputStream.readInt();
System.out.println(n);
}
}
catch(EOFException e)
{
System.out.println("End of reading from file.");
}
inputStream.close();
}
catch(FileNotFoundException e)
{
System.out.println("Cannot find file numbers.dat.");
}
catch(IOException e)
{
System.out.println("Problem with input from file numbers.dat.");
}
49
Read & Echo
import java.io.*;
public class Echo {
public static void main(String[] args) {
echo(System.in);
}
public static void echo(InputStream in) {
try { while (true)
{ // Notice that although a byte is read, an int
// with value between 0 and 255 is returned.
// Then this is converted to an ISO Latin-1 char
// in the same range before being printed.
int i = in.read(); // -1 is returned to indicate the end of stream
if (i == -1) break; // without the cast a numeric string like "65"
// would be printed instead of the character "A"
char c = (char) i;
System.out.print(c);
}
} catch (IOException e) { System.err.println(e); }
System.out.println();
}