AhmadLang / Java, How To Program, 2004
.pdf
59record = new RandomAccessAccountRecord(
60record.getAccount(), record.getFirstName(),
61record.getLastName(), record.getBalance() + transaction );
63record.write( file ); // write updated record to file
64} // end method updateRecord
66// add record to file
67public void newRecord( int accountNumber, String firstName,
68String lastName, double balance )
69throws IllegalArgumentException, IOException
70{
71RandomAccessAccountRecord record = getRecord( accountNumber );
73if ( record.getAccount() != 0 )
74 |
throw new IllegalArgumentException( "Account already exists" ); |
75 |
|
76// seek appropriate record in file
77file.seek( ( accountNumber - 1 ) * RandomAccessAccountRecord.SIZE );
79record = new RandomAccessAccountRecord( accountNumber,
80 |
firstName, lastName, balance ); |
81 |
|
82record.write( file ); // write record to file
83} // end method newRecord
84
85// delete record from file
86public void deleteRecord( int accountNumber )
87throws IllegalArgumentException, IOException
88{
89RandomAccessAccountRecord record = getRecord( accountNumber );
91if ( record.getAccount() == 0 )
92 |
throw new IllegalArgumentException( "Account does not exist" ); |
93 |
|
94// seek appropriate record in file
95file.seek( ( accountNumber - 1 ) * RandomAccessAccountRecord.SIZE );
97// create a blank record to write to the file
98record = new RandomAccessAccountRecord();
99record.write( file );
100} // end method deleteRecord
102// read and display records
103public void readRecords()
104{
105RandomAccessAccountRecord record = new RandomAccessAccountRecord();
107System.out.printf( "%-10s%-15s%-15s%10s\n", "Account",
108 |
"First Name", "Last Name", "Balance" ); |
109 |
|
110try // read a record and display
111{
112file.seek( 0 );
113
114while ( true )
115{
116 |
do |
|
|
|
117 |
{ |
|
|
|
118 |
|
record.read( file ); |
||
119 |
} |
while ( |
record.getAccount() == 0 ); |
|
120 |
|
|
|
|
121 |
// |
display |
record |
contents |
122 |
System.out.printf( |
"%-10d%-15s%-15s%10.2f\n", |
||
123 |
|
record.getAccount(), record.getFirstName(), |
||
124 |
|
record.getLastName(), record.getBalance() ); |
||
125} // end while
126} // end try
127catch ( EOFException eofException ) // close file
128{
129return; // end of file was reached
130} // end catch
131catch ( IOException ioException )
132{
133System.err.println( "Error reading file." );
134System.exit( 1 );
135} // end catch
136} // end method readRecords
137} // end class FileEditor
[Page 723]
Class transactionProcessor (Fig. 14.35) displays the menu for the application and manages the interactions with the FileEditor object that is created in the openFile method (lines 2034).
Figure 14.35. Transaction-processing program.
(This item is displayed on pages 723 - 726 in the print version)
1 // Fig. 14.35: TransactionProcessor.java
2 // A transaction processing program using random-access files.
3import java.io.IOException;
4import java.util.NoSuchElementException;
5import java.util.Scanner;
6
7 import com.deitel.jhtp6.ch14.RandomAccessAccountRecord; 8
9public class TransactionProcessor
10{
11private FileEditor dataFile;
12private RandomAccessAccountRecord record;
13private MenuOption choices[] = { MenuOption.PRINT,
14MenuOption.UPDATE, MenuOption.NEW,
15MenuOption.DELETE, MenuOption.END };
16
17 private Scanner input = new Scanner( System.in ); 18
19// get the file name and open the file
20private boolean openFile()
21{
22try // attempt to open file
23{
24// call the helper method to open the file
25dataFile = new FileEditor( "clients.dat" );
26} // end try
27catch ( IOException ioException )
28{
29System.err.println( "Error opening file." );
30return false;
31} // end catch
32
33return true;
34} // end method openFile
36// close file and terminate application
37private void closeFile()
38{
39try // close file
40{
41dataFile.closeFile();
42} // end try
43catch ( IOException ioException )
44{
45System.err.println( "Error closing file." );
46System.exit( 1 );
47} // end catch
48} // end method closeFile
49
50// create, update or delete the record
51private void performAction( MenuOption action )
52{
53int accountNumber = 0; // account number of record
54String firstName; // first name for account
55String lastName; // last name for account
56double balance; // account balance
57double transaction; // amount to change in balance
59try // attempt to manipulate files based on option selected
60{
61switch ( action ) // switch based on option selected
62{
63 |
case PRINT: |
64 |
System.out.println(); |
65 |
dataFile.readRecords(); |
66 |
break; |
67 |
case NEW: |
68 |
System.out.printf( "\n%s%s\n%s\n%s", |
69 |
"Enter account number,", |
70 |
" first name, last name and balance.", |
71 |
"(Account number must be 1 - 100)", "? " ); |
72 |
|
73 |
accountNumber = input.nextInt(); // read account number |
74 |
firstName = input.next(); // read first name |
75 |
lastName = input.next(); // read last name |
76 |
balance = input.nextDouble(); // read balance |
77 |
|
78 |
dataFile.newRecord( accountNumber, firstName, |
79 |
lastName, balance ); // create new record |
80 |
break; |
81 |
case UPDATE: |
82 |
System.out.print( |
83 |
"\nEnter account to update ( 1 - 100 ): " ); |
84 |
accountNumber = input.nextInt(); |
85 |
record = dataFile.getRecord( accountNumber ); |
86 |
|
87 |
if ( record.getAccount() == 0 ) |
88 |
System.out.println( "Account does not exist." ); |
89 |
else |
90 |
{ |
91 |
// display record contents |
92 |
System.out.printf( "%-10d%-12s%-12s%10.2f\n\n", |
93 |
record.getAccount(), record.getFirstName(), |
94 |
record.getLastName(), record.getBalance() ); |
95 |
|
96 |
System.out.print( |
97 |
"Enter charge ( + ) or payment ( - ): " ); |
98 |
transaction = input.nextDouble(); |
99 |
dataFile.updateRecord( accountNumber, // update record |
100 |
transaction ); |
101 |
|
102 |
// retrieve updated record |
103 |
record = dataFile.getRecord( accountNumber ); |
104 |
|
105 |
// display updated record |
106 |
System.out.printf( "%-10d%-12s%-12s%10.2f\n", |
107 |
record.getAccount(), record.getFirstName(), |
108 |
record.getLastName(), record.getBalance() ); |
109 |
} // end else |
110 |
break; |
111 |
case DELETE: |
112 |
System.out.print( |
113 |
"\nEnter an account to delete (1 - 100): " ); |
114 |
accountNumber = input.nextInt(); |
115 |
|
116 |
dataFile.deleteRecord( accountNumber ); // delete record |
117 |
break; |
118 |
default: |
119 |
System.out.println( "Invalid action." ); |
120 |
break; |
121} // end switch
122} // end try
123catch ( NumberFormatException format )
124{
125System.err.println( "Bad input." );
126} // end catch
127catch ( IllegalArgumentException badAccount )
128{
129System.err.println( badAccount.getMessage() );
130} // end catch
131catch ( IOException ioException )
132{
133System.err.println( "Error writing to the file." );
134} // end catch
135catch ( NoSuchElementException elementException )
136{
encapsulates the file-processing operations in this example. The method to call is determined by performAction's MenuOption argument. Each option is handled in the switch statement of lines 61121. Method performAction also handles any exceptions that might be thrown from FileEditor's methods.
[Page 727]
slow compared with the speed of accessing computer memory. Buffering reduces the number of I/O operations by first combining smaller outputs together in memory. The number of actual physical I/O operations is small compared with the number of I/O requests issued by the program. Thus, the program that is using buffering is more efficient.
Performance Tip 14.1
Buffered I/O can yield significant performance improvements over unbuffered I/O.
With a BufferedInputStream (a subclass of class FilterInputStream), many "logical" chunks of data from a file are read as one large physical input operation into a memory buffer. As a program requests each new chunk of data, it is taken from the buffer. (This procedure is sometimes referred to as a logical input operation.) When the buffer is empty, the next actual physical input operation from the input device is performed to read in the next group of "logical" chunks of data. Thus, the number of actual physical input operations is small compared with the number of read requests issued by the program.
Earlier in the chapter we used class StringBuffer, which allows us to dynamically manipulate strings. It is important to note that class StringBuffer can be used to buffer output that will be displayed later to the screen or in a JTextArea. This increases the efficiency of a programjust as with buffering, it is much faster to first combine all the program's output in a StringBuffer object and display the final output to a JTextArea or the screen, then to continually add text to a JTextArea or the screen. We discuss class StringBuffer in more detail in Chapter 29, Strings, Characters and Regular Expressions.
Java stream I/O includes capabilities for inputting from byte arrays in memory and outputting to byte arrays in memory. A ByteArrayInputStream (a subclass of InputStream) reads from a byte array in memory. A ByteArrayOutputStream (a subclass of OutputStream) outputs to a byte array in memory. One use of byte-array I/O is data validation. A program can input an entire line at a time from the input stream into a byte array. Then a validation routine can scrutinize the contents of the byte array and correct the data if necessary. Finally, the program can proceed to input from the byte array, "knowing" that the input data is in the proper format. Outputting to a byte array is a nice way to take advantage of the powerful output-formatting capabilities of Java streams. For example, data can be stored in a byte array, using the same formatting that will be displayed at a later time, and the byte array can then be output to a disk file to preserve the screen image.
A SequenceInputStream (a subclass of InputStream) enables concatenation of several InputStreams, which means that the program sees the group as one continuous InputStream. When the program reaches the end of an input stream, that stream closes, and the next stream in the sequence opens.
[Page 729]
Interfaces and Classes for Character-Based Input and Output
In addition to the byte-based streams, Java provides the Reader and Writer abstract classes, which are Unicode two-byte, character-based streams. Most of the byte-based streams have corresponding character-based concrete Reader or Writer classes.
Classes BufferedReader (a subclass of abstract class Reader) and BufferedWriter (a subclass of abstract class Writer) enable buffering for character-based streams. Remember that character-based streams use Unicode characterssuch streams can process data in any language that the Unicode character set represents.
Classes CharArrayReader and CharArrayWriter read and write, respectively, a stream of characters to a character array. A LineNumberReader (a subclass of BufferedReader) is a buffered character stream that keeps track of the number of lines read (i.e., a newline, a return or a carriage- returnline-feed combination). Keeping track of line numbers can be useful if the program needs to inform the reader of an error on a specific line.
Class FileReader (a subclass of InputStreamReader) and class FileWriter (a subclass of
OutputStreamWriter) read characters from and write characters to a file, respectively. Class PipedReader and class PipedWriter implement piped-character streams that can be used to
transfer information between threads. Class StringReader and StringWriter read characters from and write characters to Strings, respectively. A PrintWriter writes characters to a stream.
