Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

AhmadLang / Java, How To Program, 2004

.pdf
Скачиваний:
630
Добавлен:
31.05.2015
Размер:
51.82 Mб
Скачать

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{

137System.err.println( "Invalid input. Please try again." );

138input.nextLine(); // discard input so user can try again

139} // end catch

140} // end method performAction

141

142// enable user to input menu choice

143private MenuOption enterChoice()

144{

145int menuChoice = 1;

146

147// display available options

148System.out.printf( "\n%s\n%s\n%s\n%s\n%s\n%s",

149"Enter your choice", "1 - List accounts",

150"2 - Update an account", "3 - Add a new account",

151"4 - Delete an account", "5 - End program\n? " );

153try

154{

155menuChoice = input.nextInt();

156}

157catch ( NoSuchElementException elementException )

158{

159System.err.println( "Invalid input." );

160System.exit( 1 );

161} // end catch

162

163return choices[ menuChoice - 1 ]; // return choice from user

164} // end enterChoice

165

166public void processRequests()

167{

168openFile();

169

170// get user's request

171MenuOption choice = enterChoice();

173while ( choice != MenuOption.END )

174{

175performAction (choice );

176choice = enterChoice();

177} // end while

178

179closeFile();

180} // end method processRequests

181} // end class TransactionProcessor

Figure 14.36. Testing class transactionProcessor.

(This item is displayed on page 726 in the print version)

1// Fig. 14.36: TransactionProcessorTest.java

2// Testing the transaction processor.

3

4public class TransactionProcessorTest

5{

6public static void main( String args[] )

7{

8TransactionProcessor application = new TransactionProcessor();

9application.processRequests();

10} // end main

11} // end class TransactionProcessorTest

[Page 726]

Method processRequests (lines 166180) processes the choices entered by the user. If the user does not enter 5 (which ends the program), method performAction (lines 51140) is called. This method inputs information from the user and sends it to the appropriate method of class FileEditor (Fig. 14.34), which

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]

[Page 727 (continued)]

14.8. Additional java.io Classes

We now introduce you to other useful classes in the java.io package. We overview additional interfaces and classes for byte-based input and output streams, and character-based input and output streams.

Interfaces and Classes for Byte-Based Input and Output

InputStream and OutputStream (subclasses of Object) are abstract classes that declare methods for performing byte-based input and output, respectively. We used concrete classes

FileInputStream (a subclass of InputStream) and FileOutputStream (a subclass of OutputStream) to manipulate files in this chapter.

Pipes are synchronized communication channels between threads. We discuss threads in Chapter 23, Multithreading. Java provides PipedOutputStream (a subclass of OutputStream) and

PipedInputStream (a subclass of InputStream) to establish pipes between two threads in a program. One thread sends data to another by writing to a PipedOutputStream. The target thread reads information from the pipe via a PipedInputStream.

A FilterInputStream filters an InputStream, and a FilterOutputStream filters an

OutputStream. Filtering means simply that the filter stream provides additional functionality, such as aggregating data bytes into meaningful primitive-type units. FilterInputStream and FilterOutputStream are abstract classes, so some of their filtering capabilities are provided by their concrete subclasses.

A PrintStream (a subclass of FilterOutputStream) performs text output to the specified stream. Actually, we have been using PrintStream output throughout the text to this pointSystem.out and

System.err are PrintStream objects.

Reading data as raw bytes is fast, but crude. Usually, programs read data as aggregates of bytes that form ints, floats, doubles and so on. Java programs can use several classes to input and output data in aggregate form.

Interface DataInput (discussed in Section 14.7.1) describes methods for reading primitive types from an input stream. Classes DataInputStream and RandomAccessFile each implement this interface to read sets of bytes and view them as primitive-type values. Interface DataInput includes methods

readLine (for byte arrays), readBoolean, readByte, readChar, readDouble, readFloat, readFully (for byte arrays), readInt, readLong, readShort, readUnsignedByte, readUnsignedShort, readUTF (for reading Unicode characters encoded by Javawe discuss UTF encoding in Appendix F, Unicode®) and skipBytes.

Interface DataOutput (discussed in Section 14.7.1) describes a set of methods for writing primitive types to an output stream. Classes DataOutputStream (a subclass of FilterOutputStream) and RandomAccessFile each implement this interface to write primitive-type values as bytes. Interface DataOutput includes overloaded versions of method write (for a byte or for a byte array) and methods

writeBoolean, writeByte, writeBytes, writeChar, writeChars (for Unicode Strings), writeDouble, writeFloat, writeInt, writeLong, writeShort and writeUTF (to output text modified for Unicode).

Buffering is an I/O-performance-enhancement technique. With a BufferedOutputStream (a subclass of class FilterOutputStream), each output statement does not necessarily result in an actual physical transfer of data to the output device (which is a slow operation compared to processor and main memory speeds). Rather, each output operation is directed to a region in memory called a buffer that is large enough to hold the data of many output operations. Then, actual transfer to the output device is performed in one large physical output operation each time the buffer fills. The output operations directed to the output buffer in memory are often called logical output operations. With a BufferedOutputStream, a partially filled buffer can be forced out to the device at any time by invoking the stream object's flush method.

[Page 728]

Using buffering can greatly increase the efficiency of an application. Typical I/O operations are extremely

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.

[Page 729 (continued)]

14.9. Opening Files with JFileChooser

We conclude this chapter by introducing class JFileChooser. We use this class to display a dialog (known as the JFileChooser dialog) that enables users of our program to easily select files. To demonstrate the JFileChooser dialog, we enhance the example in Section 14.4, as shown in Fig. 14.37Fig. 14.38. The example now contains a graphical user interface, but still displays the same data as before. The constructor calls method analyzePath in line 34. This method then calls method getFile in line 68 to retrieve the File object.

Figure 14.37. Demonstrating JFileChooser.

(This item is displayed on pages 730 - 731 in the print version)

1// Fig. 14.37: FileDemonstration.java

2// Demonstrating the File class.

3import java.awt.BorderLayout;

4import java.awt.event.ActionEvent;

5import java.awt.event.ActionListener;

6import java.io.File;

7import javax.swing.JFileChooser;

8import javax.swing.JFrame;

9import javax.swing.JOptionPane;

10import javax.swing.JScrollPane;

11import javax.swing.JTextArea;

12import javax.swing.JTextField;

13

14public class FileDemonstration extends JFrame

15{

16private JTextArea outputArea; // used for output

17private JScrollPane scrollPane; // used to provide scrolling to output

19// set up GUI

20public FileDemonstration()

21{

22super( "Testing class File" );

24outputArea = new JTextArea();

26// add outputArea to scrollPane

27scrollPane = new JScrollPane( outputArea );

29add( scrollPane, BorderLayout.CENTER ); // add scrollPane to GUI

31setSize( 400, 400 ); // set GUI size

32setVisible( true ); // display GUI

34analyzePath(); // create and analyze File object

35} // end FileDemonstration constructor

37// allow user to specify file name

38private File getFile()

39{

40// display file dialog, so user can choose file to open

41JFileChooser fileChooser = new JFileChooser();

42fileChooser.setFileSelectionMode(

43JFileChooser.FILES_AND_DIRECTORIES );

44

45 int result = fileChooser.showOpenDialog( this );

46

47// if user clicked Cancel button on dialog, return

48if ( result == JFileChooser.CANCEL_OPTION )

49System.exit( 1 );

50

51 File fileName = fileChooser.getSelectedFile(); // get selected file 52

53 // display error if invalid

54 if ( ( fileName == null ) || ( fileName.getName().equals( "" ) ) )

55{

56JOptionPane.showMessageDialog( this, "Invalid File Name",

57

"Invalid File Name", JOptionPane.ERROR_MESSAGE );

58System.exit( 1 );

59} // end if

60

61return fileName;

62} // end method getFile

64// display information about file user specifies

65public void analyzePath()

66{

67// create File object based on user input

68File name = getFile();

69

70 if ( name.exists() ) // if name exists, output information about it

71{

72// display file (or directory) information

73outputArea.setText( String.format(

74

"%s%s\n%s\n%s\n%s\n%s%s\n%s%s\n%s%s\n%s%s\n%s%s",

75

name.getName(), " exists",

76

( name.isFile() ? "is a file" : "is not a file" ),

77

( name.isDirectory() ? "is a directory" :

78

"is not a directory" ),

79

( name.isAbsolute() ? "is absolute path" :

80

"is not absolute path" ), "Last modified: ",

81

name.lastModified(), "Length: ", name.length(),

82

"Path: ", name.getPath(), "Absolute path: ",

83

name.getAbsolutePath(), "Parent: ", name.getParent() ) );

84

 

85if ( name.isDirectory() ) // output directory listing

86{

87

String directory[]

= name.list();

88

outputArea.append(

"\n\nDirectory contents:\n" );

89

 

 

90

for ( String directoryName : directory )

91

outputArea.append( directoryName + "\n" );

92} // end else

93} // end outer if

94else // not file or directory, output error message

95{

96JOptionPane.showMessageDialog( this, name +

97

" does not exist.", "ERROR", JOptionPane.ERROR_MESSAGE );

98} // end else

99} // end method analyzePath

100} // end class FileDemonstration

Figure 14.38. Testing class FileDemonstration.

(This item is displayed on page 732 in the print version)

1// Fig. 14.38: FileDemonstrationTest.java

2// Testing the FileDmonstration class.

3import javax.swing.JFrame;

4

5public class FileDemonstrationTest

6{

7public static void main( String args[] )

8{

9FileDemonstration application = new FileDemonstration();

10application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

11} // end main

12} // end class FileDemonstrationTest

[View full size image]