Download Notes

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Week 7:
(Horstman ch.15, 16, Deite&Deitel ch.16 and Lewis&Loftus ch.8.4)
Exception Handling
We encountered already exception handling in ITEC1620, when reading from an external file.
import java.util.Scanner;
import java.io.*;
public class ExampleFile{
public static void main(String[] args) throws IOException{
Scanner fileInput = new Scanner(new File("input.txt"));
PrintStream fileOutput = new PrintStream(new File("output.txt"));
int sum = 0;
for( ; fileInput.hasNextInt(); ){
sum = sum + fileInput.nextInt();
}
fileOutput.println("The sum is: " + sum);
fileInput.close();
fileOutput.close();
}
}
where the content of the file input.txt was:
1
2
3
4
5
6
7
IOException is a case of checked exception and the compiler checks that the programmer does not
ignore it. A checked exception describes a problem that is likely to occur no matter how careful
you are. Input/output and systems operations are typical cases of checked exceptions. Your
program has to throw all checked exceptions.
On the other hand errors that you make as a programmer are called unchecked exceptions and you
are not forced to deal with them. Such errors are a division by zero, referring to an element outside
the size of an array. Good programming requires that you deal with these exceptions too but if you
do not your program will still compile.
Every exception should be handled somewhere in your program. If an exception has no handler an
error message is printed and your program terminates. This is not what a professionally written
program should do. You can install an exception handler with the try/catch statement.
import java.util.Scanner;
import java.io.*;
public class ExampleFile1{
public static void main(String[] args) {
int sum = 0;
Scanner fileInput=null;
PrintStream fileOutput=null;
try {
fileInput = new Scanner(new File("input.txt"));
fileOutput = new PrintStream (new File("output.txt"));
for( ; fileInput.hasNextLine(); ){
String s = fileInput.nextLine();
sum = sum + Integer.parseInt(s);
}
}
catch (IOException exception) {
System.out.println("File not found");
}
catch (NumberFormatException exception) {
System.out.println("Input was not a number");
}
finally{
fileOutput.println("The sum is: " + sum);
fileInput.close();
fileOutput.close();
}
}
}
The try block contains several sources of error and one can use several catch blocks to address
them. The File class constructor might not find the input file and will throw a
FileNotFoundException (which is a possible IOException). In the catch corresponding to that
exception there is clear message. The second source of exception is Integer.parseInt(s) in cases
when the input file contains a non-numeric input. This is an unchecked RuntimeException, which is
caught to create a clear error message.
Independent of whether an exception was made or not one must close the files and these statements
are put in the finally block.
Files and I/O Streams
Storage of data in variables and arrays is temporary – the data is lost when the program terminates.
You have to use files for long-term retention of data. Like programs, files can be stored on storage
devices such as magnetic or optical disks.
Data Hierarchy. The smallest data item is the bit. The next is the character and Java uses Unicode
characters built of 2 bytes each (ie 16 bits). Some files work with characters: text files, image files,
audio files. But in many industries, such as banking, data is further organized in fields and records.
A field is a sequence of characters that convey some meaning. For instance a name can be a field.
A record contains several fields. For instance an employee record in a payroll system has:
employee number, name, pay rate, year-to-date earnings, taxes withheld (the first 2 fields are
Strings, the next 3 are doubles).
To facilitate the retrieval of specific records one field of the record is chosen as record key. In the
above example employee number is most suitable to be a record key. The most common
organization of a file of records is the randon-access file, in which records are stored in order by
the record key field.
Most businesses have many different files: payroll, accounts receivable, accounts payable,
inventory etc. Often a group of files is called a database.
Files and Streams. Java views each file either as a stream of bytes or characters. Its package
java.io contains classes FileInputStream and FileOutputStream for streams of bytes and FileReader
and FileWriter for streams of characters.
Reading a Text File.
The easiest scenario is using a text file created with Notepad or any other text editor. In this case
one uses the FileReader and BufferedReader classes. The second class filters data by buffering it
into more accessible units. It uses the method readLine() to obtain a String which is then broken
into components with a StringTokenizer object. The latest versions of JDK offered in addition
classes Scanner and File, which can be used to replace BufferedReader and FileReader,
respectively.
import java.util.StringTokenizer;
import java.io.*;
import java.text.DecimalFormat;
class InventoryItem {
private String name;
private int units; // number of available units of this item
private float price; // price per unit of this item
private DecimalFormat fmt;
public InventoryItem (String itemName, int numUnits, float cost) {
name = itemName;
units = numUnits;
price = cost;
fmt = new DecimalFormat ("0.##");
}
public String toString() {
return name + ":\t" + units + " at " + price + " = " +
fmt.format ((units * price));
}
}
public class Inventory{
//-----------------------------------------------------------------
// Reads data about a store inventory from an input file,
// creating an array of InventoryItem objects, then prints them.
//----------------------------------------------------------------public static void main (String[] args) {
final int MAX = 100;
InventoryItem[] items = new InventoryItem[MAX];
StringTokenizer tokenizer;
String line, name, file="inventory.dat";
int units, count = 0;
float price;
try
{
BufferedReader inFile = new BufferedReader (new FileReader (file));
line = inFile.readLine();
while (line != null)
{
tokenizer = new StringTokenizer (line);
name = tokenizer.nextToken();
try
{
units = Integer.parseInt (tokenizer.nextToken());
price = Float.parseFloat (tokenizer.nextToken());
items[count++] = new InventoryItem (name, units, price);
}
catch (NumberFormatException exception)
{
System.out.println ("Error in input. Line ignored:");
System.out.println (line);
}
line = inFile.readLine();
}
inFile.close();
for (int scan = 0; scan < count; scan++)
System.out.println (items[scan]);
}
catch (FileNotFoundException exception)
{
System.out.println ("The file " + file + " was not found.");
}
catch (IOException exception)
{
System.out.println (exception);
}
}
}
The input file is shown below:
Widget 14 3.35
Spoke 132 0.32
Wrap 58 1.92
Thing 28 4.17
Brace 25 1.75
Clip 409 0.12
Cog 142 2.08
Writing a Text File.
Writing output to a text file requires the use of classes FileWriter, BufferedWriter and PrintWriter.
(or in the latest versions of JDK classes File and PrintWriter). In the example below one computes
random values which are then printed to an external file (the file is created by this program).
import java.io.*;
public class TestData {
//----------------------------------------------------------------// Creates a file of test data that consists of ten lines each
// containing ten integer values in the range 0 to 99.
//----------------------------------------------------------------public static void main (String[] args) throws IOException {
final int MAX = 10;
int value;
String file = "test.dat";
PrintWriter outFile = new PrintWriter (new BufferedWriter (new FileWriter (file)));
for (int line=1; line <= MAX; line++)
{
for (int num=1; num <= MAX; num++)
{
value = (int) (Math.random() * 100);
outFile.print (value + " ");
}
outFile.println ();
}
outFile.close();
System.out.println ("Output file has been created: " + file);
}
}
Sequential and Random-Access Files
What if we want to store complex objects into files ? These objects would correspond to records in
a database. Persistence is the concept that an object can “live” outside the program that created it.
Files do not have a record structure, but programs can impose a record structure on a file. Java
contains a mechanism called object serialization, which transforms an object into a sequence of
bytes. Any object that we want to serialize must implement the interface Serializable. To serialize
one uses the method writeObject() of the class ObjectOutputStream, which works in conjunction
with the class FileOutputStream.
Java allows for two types of records-based files to be created. The sequential files are like an oldfashioned music tape, where records of various length are in a sequence. One always have to start
from the beginning of the tape to reach anywhere inside the tape. Random-access files are similar
to a CD player. One can jump to a certain record if one knows its address (index). Obviously
random-access files are more convenient to operate with. They are easier to update and easier to
program. We shall restrict our discussion to random-access files. One more observation: like the
sequential files, random-access files cannot be read with a text editor, as they are byte and not
character-based. To read it and display each record one needs the following Java program.
Random Access Files.
For quick access to a certain record one has to use random-access files. The price for having this
feature is that the file will be with fixed-length records. The structure of the file has to be decided
before the loading of data. The following two programs will do that task. The first program will
define a class that is used for reading and writing records to a random-access file. The second
program will create a file with blank records.
// Record class for the RandomAccessFile programs.
import java.io.*;
public class Record {
int account;
String lastName;
String firstName;
double balance;
// Read a record from the specified RandomAccessFile
public void read( RandomAccessFile file ) throws IOException {
account = file.readInt();
byte b1[] = new byte[ 15 ];
file.readFully( b1 );
firstName = new String( b1, 0 );
firstName=firstName.trim();
byte b2[] = new byte[ 15 ];
file.readFully( b2 );
lastName = new String( b2, 0 );
lastName=lastName.trim();
balance = file.readDouble();
}
// Write a record to the specified RandomAccessFile
public void write( RandomAccessFile file ) throws IOException {
file.writeInt( account );
byte b1[] = new byte[ 15 ];
if ( firstName != null )
firstName.getBytes( 0, firstName.length(), b1, 0 );
file.write( b1 );
byte b2[] = new byte[ 15 ];
if ( lastName != null )
lastName.getBytes( 0, lastName.length(), b2, 0 );
file.write( b2 );
file.writeDouble( balance );
}
// NOTE: This method contains a hard coded value for the size of a record of information.
public int size() { return 42; }
}
//==========================================================
// This program creates a random access file sequentially by writing 100 empty records to disk.
import java.io.*;
public class CreateRandFile {
private Record blank;
RandomAccessFile file;
public CreateRandFile() {
blank = new Record();
try {
file = new RandomAccessFile( "credit.dat", "rw" );
}
catch( IOException e ) {
System.err.println( "File not opened properly\n" +
e.toString() );
System.exit( 1 );
}
}
public void create() {
try {
for ( int i = 0; i < 100; i++ )
blank.write( file );
}
catch ( IOException e ) {
System.err.println( e.toString() );
}
}
public static void main( String args[] ) {
CreateRandFile accounts = new CreateRandFile();
accounts.create();
}
}
Having the empty records on the disk we can add records to
the file by using the RandomAccessFile method seek() to
determine the location to be stored.
// This program uses TextFields to get information from the
// user at the keyboard and writes the information to a random access file.
import java.io.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class WriteRandFile extends JFrame {
// Application window components
JTextField acct,
// where user enters account number
fName, // where user enters first name
lName, // where user enters last name
bal;
// where user enters balance
JButton enter,
// send record to file
done;
// quit program
JLabel acctLabel, // account label
fNameLabel, // first name label
lNameLabel, // last name label
balLabel;
// balance label
RandomAccessFile output; // file for output
Record data;
public WriteRandFile() {
super( "Write to random access file" );
data = new Record();
try {
output = new RandomAccessFile( "credit.dat", "rw" );
}
catch ( IOException e ) {
System.err.println( e.toString() );
System.exit( 1 );
}
Container c = getContentPane();
c.setLayout( new GridLayout( 5, 2 ) );
acct = new JTextField( 20 );
acctLabel = new JLabel( "Account Number" );
fName = new JTextField( 20 );
fNameLabel = new JLabel( "First Name" );
lName = new JTextField( 20 );
lNameLabel = new JLabel( "Last Name" );
bal = new JTextField( 20 );
balLabel = new JLabel( "Balance" );
enter = new JButton( "Enter" );
done = new JButton( "Done" );
c.add( acctLabel ); // add label
c.add( acct );
// add TextField
c.add( fNameLabel ); // add label
c.add( fName );
// add TextField
c.add( lNameLabel ); // add label
c.add( lName );
// add TextField
c.add( balLabel ); // add label
c.add( bal );
// add TextField
c.add( enter );
// add button
c.add( done );
// add button
done.addActionListener(
new ActionListener () {
public void actionPerformed( ActionEvent event ){
cleanup(); // write data, close file, etc.
hide();
dispose(); // release system resources
System.exit( 0 );
}}
);
enter.addActionListener(
new ActionListener () {
public void actionPerformed( ActionEvent event ){
addRecord();
}}
);
setSize( 300, 150 );
setVisible( true );
}
public void addRecord() {
int acctNum = 0;
Double d;
acctNum = ( new Integer( acct.getText() ) ).intValue();
// output the values to the file
try {
if ( acctNum > 0 && acctNum <= 100 ) {
data.account = acctNum;
data.firstName = fName.getText();
data.lastName = lName.getText();
d = new Double ( bal.getText() );
data.balance = d.doubleValue();
output.seek( (long) ( acctNum-1 ) * data.size() );
data.write( output );
// clear the TextFields
acct.setText( "" );
fName.setText( "" );
lName.setText( "" );
bal.setText( "" );
}
else {
acct.setText( "Enter valid account (1-100)" );
acct.selectAll();
}
}
catch ( IOException e ) {
System.err.println( "Error during write to file\n" +
e.toString() );
System.exit( 1 );
}
}
public void cleanup() {
if ( !acct.getText().equals("") )
addRecord();
try {
output.close();
}
catch ( IOException e ) {
System.err.println( "File not closed properly\n" +
e.toString() );
System.exit( 1 );
}
}
public static void main( String args[] ) {
WriteRandFile accounts = new WriteRandFile();
}
}
The following program opens a random-access file and displays only the records with data.
// This program uses TextFields to get information from the
// user at the keyboard and writes the information to a random access file.
import java.io.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class ReadRandFile extends JFrame {
// Application window components
JTextField acct,
// where user enters account number
fName, // where user enters first name
lName, // where user enters last name
bal;
// where user enters balance
JButton next,
// send record to file
done;
// quit program
JLabel acctLabel, // account label
fNameLabel, // first name label
lNameLabel, // last name label
balLabel;
// balance label
RandomAccessFile input; // file for output
Record data;
boolean moreRecords=true;
public ReadRandFile() {
super( "Write to random access file" );
data = new Record();
try {
input = new RandomAccessFile( "credit.dat", "r" );
}
catch ( IOException e ) {
System.err.println( e.toString() );
System.exit( 1 );
}
Container c = getContentPane();
c.setLayout( new GridLayout( 5, 2 ) );
acct = new JTextField( 20 );
acctLabel = new JLabel( "Account Number" );
fName = new JTextField( 20 );
fNameLabel = new JLabel( "First Name" );
lName = new JTextField( 20 );
lNameLabel = new JLabel( "Last Name" );
bal = new JTextField( 20 );
balLabel = new JLabel( "Balance" );
next = new JButton( "Next" );
done = new JButton( "Done" );
c.add( acctLabel ); // add label
c.add( acct );
// add TextField
c.add( fNameLabel ); // add label
c.add( fName );
// add TextField
c.add( lNameLabel ); // add label
c.add( lName );
// add TextField
c.add( balLabel ); // add label
c.add( bal );
// add TextField
c.add( next );
// add button
c.add( done );
// add button
done.addActionListener(
new ActionListener () {
public void actionPerformed( ActionEvent event ){
cleanup(); // write data, close file, etc.
hide();
dispose(); // release system resources
System.exit( 0 );
}}
);
next.addActionListener(
new ActionListener () {
public void actionPerformed( ActionEvent event ){
readRecord();
}}
);
setSize( 300, 150 );
setVisible( true );
}
public void readRecord() {
try {
do { // loop over empty records
data.read( input );
} while ( input.getFilePointer() < input.length() &&
data.account == 0 );
}
catch( IOException e ) {
moreRecords = false;
}
// transfer full record data into textfields
if ( data.account != 0 ) {
acct.setText( String.valueOf( data.account ) );
String fN=data.firstName;
fName.setText( fN);
String lN=data.lastName;
lName.setText( lN );
bal.setText( String.valueOf( data.balance ) );
}
}
public void cleanup() {
try {
input.close();
}
catch ( IOException e ) {
System.err.println( e.toString() );
System.exit( 1 );
}
}
public static void main( String args[] ) {
ReadRandFile accounts = new ReadRandFile();
}
}
The use of random-access files allows for the creation of a good transaction-processing program,
able to perform quick retrieval and update of records. Such a program will contain part of the code
discussed in the previous examples:
- for inserting a new record one can use the code of Ex.10.4 and knowledge on which record
spaces are still free
- for the delete of a specified record one just replaces that record with a blanc record
- for the update of a record one retrieves the record with the code of Ex.10.5 and then the user
can modify the information now present in textfields. When finished the record is sent back
to the file with code of Ex.10.4.
Note that all this work is extremely long and complicated with sequential files, where work with
one record will affect the position of all subsequent records.