EE2E1 Lecture 7 old

Download Report

Transcript EE2E1 Lecture 7 old

EE2E1. JAVA Programming
Lecture 7
Files and Streams
Contents







Introduction - input and output streams
Exception handling
The stream class hierarchy
Simple file i/o
Layering streams – reading/writing formatted files
Layering streams – reading/writing gzip files
Reading and writing text files
Introduction - input and output
streams

Most applications require data to be stored in files

Spreadsheets

Word processing

etc

Java has extensive facilities for handling files of
various types

Associated with files is the general concept of
streams which can be applied to both files and
networks

In Java, streams are simply sequences of bytes

We can read a byte stream from an input stream
object

We can write a byte stream to an output stream
object

Typically input and output stream objects can be
files but they also can be network connections

This generality means we can use the same
functions for accessing networks as reading
files
Output stream object
byte stream
Input stream object
byte stream

Java distinguishes between byte streams and
character streams
 In Java, a character is represented by a 2byte Unicode character (www.unicode.org)
Reader object
character stream
Writer object
character stream



Finally Java uses the concept of a data stream to
read and write useful data such as integers and
doubles (as opposed to just bytes and characters)
 Java uses a mechanism called layering to attach
these different types of streams together
 For example we can attach an input stream to a
file and then attach a data input stream to the
file input stream so we can read a file of
integers. (See later!)
The java.io package contains all of the classes for
input/output and streams
 Its all quite complex because of its huge
flexibility
Its even worse than that because before we can use
streams we need to know about exceptions!!
Exception handling


All Java programs which deal with files and/or
streams must include exception handling
Exceptions are error conditions encountered in
executing class methods
 Attempting to read past an end of file
 Attempting to read a file that doesn’t exist
 Trying to open a malformed URL
 Divide by zero
 Taking the square root of a negative number
 etc

Normal error handling (in C) would return
an error code (eg. –1)
class myClass
{
.
.
public int readFile(….)
{
do
{
if (!end_of_file)
// read the file
else
return –1;
} while not_end_of_file
return number_of_bytes_read;
}
}

This is a simple sometimes effective method but:
 Sometimes not possible to return a valid error
code.
 Not object oriented! No information about the
error is contained in the error code
 Application code gets ‘polluted’ with error
checking code
 It would be nice to have all of the error
handling in one place
 The method might not be able to return
normally from the error.
 An example would be if a resource the
method was accessing was not available

In Java, if an error occurs in a method, an
Exception object is thrown by the method
 Any method that calls the first method
must catch the exception in an exception
handler and take appropriate action
 After the exception is thrown and the
exception handler code executed, control
is not passed back to the caller
 We don’t have to worry about return
error codes
class myClass
{
.
.
public int myMethod
{
.
.
anObject.throwMethod(); // can throw an exception
.
return value;
// normal return point
{
// Exception handler code
// Control passed to here if
// exception thrown
}
}
}

Alternatively, the method calling throwMethod()
doesn’t want to deal with the exception, so it
throws it on to the caller of myClass.myMethod()
to worry about


The exception can be thrown along a chain of
method calls until eventually one of the
methods decides to deal with it
It can’t be ignored – at the very least the outer
method call must deal with it!
class anotherClass
{
.
public int anotherMethod
{
.
.
myObject. myMethod(); // throws on the exception
.
.
return value;
// normal return point
{
}
}
}
// Exception handler code
// Control passed to here if
// exception thrown
Throwing exceptions



A method must advertise the fact that it is going to
throw an exception of a specific type
 For example some problem with I/O
 Java differs from C++ in this respect
 Exceptions are not typed in C++
Java uses the keyword throws to indicate that a
method can throw an exception
The method actually throws the exception using
the throw keyword
class myClass
{
.
.
public int myMethod throws IOException
{
.
if (some_IO_error_condition)
throw new IOException(); // throw exception object
.
}
}
Catching exceptions

If a method calls another method which throws an
exception, that exception must either be caught or
thrown on
 If it is not, the program will terminate (nongraphical, console applications)
 or control will pass back to the user interface
processing loop (graphical applications/applets)
 In both cases, an error message will be printed

Exceptions are caught in a try/catch block
public aMethod
{
// method code which doesn’t throw an exception
try
{
// code including a call to myClass.myMethod()
// which may throw an IOException
}
catch(IOException e)
{
// Exception handler code
}
} // method ends

Execution of the above code is as follows
 If the code inside the try block throws an
exception
 The program skips the remainder of the code
in the try block
 The program then proceeds to the code in the
catch block
 If the code inside the try block doesn’t throw
an exception
 The program skips the code in the catch
block

A finally clause after a catch block contains code
which is always executed irrespective if an
exception is caught or not


Quite often it is used to release a resource
which has been allocated in the try block
For all of this to work, the exception generated
must be of the type specified (in this case, an
IOException) in the catch clause
public aMethod
{
// method code which doesn’t throw an exception
try
{
// Code which may throw an IOException
// Resource allocation
}
catch(IOException e)
{
// Exception handler code
}
finally
{
// Resource deallocation
// This code always executes
}
} // method ends

Alternatively, the exception can be thrown on
public aMethod throws IOException
{
// method code including a call to myClass.myMethod()
// which may throw an IOException
}
Exception inheritance hierarchy



Exceptions are objects encapsulating information
about the type of error which caused the exception
All exception objects derive from Throwable
2 main types of exception object
 RuntimeException
 Usually a programmer error such as divide
by zero or trying to access an array beyond
its limits
 IOException
 Not generally caused by programmer error
and generally relating to I/O or network
errors
Throwable
Exception
IOException
………
RuntimeException
………
Creating exception classes

It is easy to create our own exceptions by
extending an existing exception class
public DivideByZeroException extends ArithmeticException
{
public DivideByZeroException(String Message)
{
super(message);
}
}

The exception can then be thrown in the
usual way
class myClass
{
.
.
public double quotient(int num, int den)
throws DivideByZeroException
{
if (den==0)
throw new DivideByZeroException(“Error!”);
return ((double) num/(double)den);`
}
}
Example


The following program is a simple GUI enabling
integers to be inputted and their quotient
computed
Throws exceptions for

Incorrect integer format


NumberFormatException
Divide by zero

DivideByZeroException
http://www.eee.bham.ac.uk/spannm/Java%2
0Stuff/ExceptionTestApplet/ExceptionTestAp
plet.html
 Error dialog boxes are displayed when
exceptions are caught
 Control then passes back to the event
handling loop
 For a console based application, the
program would terminate after the
exceptions are caught


DivideByZero exception thrown in the
method quotient() (which is part of the
graphics (Applet) container class)
public double quotient(int num, int den) throws
DivideByZeroException
{
if (den==0)
throw(new DivideByZeroException());
return (double) num/(double) den;
}
public void actionPerformed(ActionEvent evt)
{
try
{
int numerator=Integer.parseInt(inputNum.getText());
int denominator=Integer.parseInt(inputDen.getText());
double result=quotient(numerator,denominator);
outputQuotient.setText(precision.format(result));
}
}
catch(NumberFormatException e)
{
JOptionPane.showMessageDialog(this," Enter 2
integers","Invalid integer format!“,
JOptionPane.ERROR_MESSAGE);
}
catch(DivideByZeroException e)
{
JOptionPane.showMessageDialog(this,"The
denominator must be non-zero",e.toString(),
JOptionPane.ERROR_MESSAGE);
}
The exceptions are caught in the event
handler class (called when ENTER is
pressed from the output result text field)
 Method quotient() throws the user
defined exception DivideByZero
exception
 Method Integer.parseInt() throws the
NumberFormatException exception
 Notice how there may be several catch()
clauses to catch multiple exceptions

The stream class hierarchy

Java has 2 abstract base classes, InputStream and
OutputStream for representing input and output
stream objects
 InputStream and OutputStream are base classes
of a large hierarchy (more than 60!) of stream
classes


For example, classes FileInputStream and
FileOutputStream allow input and output streams
to be attached to files
Java also has 2 other abstract base classes, Reader
and Writer for handling Unicode character based
I/O
InputStream
FileInputStream
………
OutputStream
FileOutputStream
………
Reader
………
Writer
………
Simple file i/o

The classes FileInputStream and
FileOutputStream give input and output to
streams attached to files
FileInputStream fin=new FileInputStream(“myFile.dat”);


This attaches an input stream to a named
file
Alternatively, we can use the File class
File f=new File(“myFile.dat”);
FileInputStream fin=new FileInputStream(f);
byte stream
FileInputStream
myFile.dat

FileInputStream has a method read() which
returns the byte read and –1 if it reaches the end of
the input stream
public int read() throws IOException

Similarly, FileOutputStream has a method write()
to write 1 byte to the output stream

Both read() and write() block the thread until
the byte is read or written

This often occurs when a network
connection is being accessed and it is busy
Example

The following program makes a straight copy of a
file and prints out the number of bytes copies
 File names provided on the command line
java FileCopyTest input_file output_file


The FileInputStream constructor throws
an IOException if the file doesn’t exist
FileInputStream.read() returns a –1 at
the end of file

We could call this method from our
own which throws an EOFException
import java.io.*;
public class FileCopyTest
{
public static void main(String[] args)
{
String inFile=args[0];
String outFile=args[1];
int nbytes=0;
try
{
FileInputStream fin=new FileInputStream(inFile);
FileOutputStream fout=new FileOutputStream(outFile);
int b=fin.read();
do
{
fout.write(b);
nbytes++;
b=fin.read();
} while (b!=-1);
}
catch (IOException e) { System.out.println("i/o problem!");}
System.out.println(nbytes + " bytes copied");
}
}
Layering streams –
reading/writing formatted files

We often want to read files containing formatted
data

For example, a file of integers or doubles

Our FileInputStream has no methods which return
numeric types – it can only read bytes

We need to combine our FileInputStream and
FileOutputStream objects with other types of
stream objects in order to read formatted files

A combination of different stream types are
known as filtered streams

A DataInputStream object can be attached
to a FileInputStream object as follows
FileInputStream fin=new FileInputStream(“myFile.dat”);
DataInputStream din=new DataInputStream(fin);
din.readDouble();
.
.
formatted
input stream
Formatted file
DataInputStream
FileInputStream
Example
The following program writes integers and
doubles to a file and then reads them back
 Uses DataInputStream.readInt() and
DataInputStream.readDouble() for
reading
 Uses DataOutputStream.writeInt() and
DataOutputStream.writeDouble() for
writing
 Catches an end of file exception

public class FormattedFileTest
{
public static void main(String[] args)
{
String fname=args[0];
try
{
FileOutputStream fout=new FileOutputStream(fname);
DataOutputStream dout=new DataOutputStream(fout);
for (int i=0; i<100; i++)
{ dout.writeInt(i); dout.writeDouble(i*0.5); }
}
catch (IOException e) { System.out.println("i/o problem!");}
try
{
FileInputStream fin=new FileInputStream(fname);
DataInputStream din=new DataInputStream(fin);
for (int j=0; j<150; j++)
{ int i=din.readInt(); double d=din.readDouble(); }
}
catch (EOFException e) { System.out.println("EOF!");}
catch (IOException e) { System.out.println("i/o problem!");}
}
}
Layering streams –
reading/writing gzip files
A Java program can read/write gzipped (and
zipped) compressed files using stream
layering
 Classes GZIPInputStream and
GZIPOutputStream enable i/o to be
performed on gzipped files
 Similarly, classes ZipInputStream and
ZipOutputStream allow i/o on zipped files


We can add a gzipped input stream to our
previous example enabling us to read
formatted data from a gzipped file!
gzipped
input stream
Zip file
DataInputStream
GZIPInputStream
FileInputStream

The following code segment shows how the
file created in the previous example can be
read after gzipping
 A file is gzipped using the UNIX
command gzip filename
.
try
{
FileInputStream fin=new FileInputStream(fname);
GZIPInputStream gin=new GZIPInputStream(fin);
DataInputStream din=new DataInputStream(gin);
for (int j=0; j<150; j++)
{ int i=din.readInt(); double d=din.readDouble(); }
}
catch (EOFException e) { System.out.println("EOF!");}
catch (IOException e) { System.out.println("i/o problem!");}
.
.
Reading and writing text files



All of our classes so far have been for binary files
 Data is stored in files as bytes which is efficient
but not humanly readable
A text file consists of information stored in
humanly readable form
 For example the number 150 would be stored
as ‘1’ ‘5’ ‘0’ instead of the binary representation
of 150 (10010110)
Java has a number of classes (descended from the
abstract Reader and Writer classes) for handling
text i/o
Outputting to a text file
This can easily be done with the PrintStream
class
 Both text and numeric data can be output
using the print() and println() methods
 Contains overloaded methods print(char
c), print(int i), print(double d), etc
 Uses a filter class (FilterOutputStream) to
convert from Unicode to readable characters


The following program segment outputs string and
numeric text to a text file
 Be clear about the difference between this and
the previous program using a binary file
.
try
{
FileOutputStream fout=new FileOutputStream(fname);
PrintStream out=new PrintStream(fout,true);
out.println(“Output data coming up”);
for (int j=0; j<150; j++)
{
out.print(j);
out.println(j*0.5);
}
}
catch (IOException e) { System.out.println("i/o problem!");}
.
Console-based input
Reading data input from the command line
in Java is not easy
 The System class has standard output, input
and error (just like C) which are already
open when the program executes
 These can be used in console-based i/o

class System
{
private
static InputStream in;
static PrintStream out;
static PrintStream err;
}

.
.
.
Console based output is easy
 We can use the methods of PrintStream
.
System.out.println(“Hello World!”);
System.out.println(“x= ” + x);
.

Console based input is more difficult
 A class Console has been written by the
authors of the Core Java book providing
convenient input methods
 readLine() returns a string
 readInt() returns an integer
 readDouble() returns a double
 readInt() and readDouble() use
readLine() to read an input string and use
string parsing to extract the numerical
value
public class Console
{
public static readLine()
{… reads a string from the keyboard…}
public static double readDouble(string prompt)
{… reads a double from the keyboard …}
public static readInt(String prompt)
{… reads an integer from the keyboard…}
}
public static String readLine()
{ int ch;
String r = "";
boolean done = false;
while (!done)
{ try
{ ch = System.in.read();
if (ch < 0 || (char)ch == '\n')
done = true;
else if ((char)ch != '\r') r = r + (char) ch;
}
catch(java.io.IOException e)
{ done = true;
}
}
return r;
}

The class is used as follows :
import Console.*;
class ConsoleTest
{
static void main(String args[])
{
int i=Console.readInt("Input an integer: ");
double d=Console.readDouble("Input a double: ");
System.out.println("Values entered= "+ i + " " + d);
}
}
And finally………



Java handling of files and streams is extensive
 We have only just scratched the surface!
Lots of other facilities are provided within the
various classes
 Buffered i/o
 Random access files
 Object streams – serialization
See chapter 12 in Core Java (Vol. 1)