20.10. Programming Exercises

 
[Page 623 ( continued )]

18.8. (Optional) Case Study: Address Book

Now let us use RandomAccessFile to create a useful project for storing and viewing an address book. The user interface of the program is shown in Figure 18.19. The Add button stores a new address at the end of the file. The First , Next , Previous , and Last buttons retrieve the first, next, previous, and last addresses from the file, respectively.


[Page 624]
Figure 18.19. AddressBook stores and retrieves addresses from a file.


Random access files are often used to process files of records. For convenience, fixed-length records are used in random access files so that a record can be located easily, as shown in Figure 18.20. A record consists of a fixed number of fields. A field can be a string or a primitive data type. A string in a fixed-length record has a maximum size. If a string is smaller than the maximum size , the rest of the string is padded with blanks.

Figure 18.20. Random access files are often used to process files of fixed-length records.

Let address.dat be the file to store addresses. A RandomAccessFile for both read and write can be created using

 RandomAccessFile raf =   new   RandomAccessFile(   "address.dat"   ,   "rw"   ); 

Let each address consist of a name (32 characters), street (32 characters), city (20 characters), state (2 characters), and zip (5 characters). If the actual size of a field (e.g., name ) is less than the fixed maximum size, fill it with blank characters. If the actual size of a field is greater than the fixed maximum size, truncate the string. Thus the total size of an address is 32 + 32 + 20 + 2 + 5 = 91 characters . Since each character occupies two bytes, one address takes 2*91 = 182 bytes. After an address record is read, the file pointer is 182 bytes ahead of the previous file pointer.

For convenience, Listing 18.8 contains two methods for reading and writing a fixed-length string.

Listing 18.8. FixedLengthStringIO.java
(This item is displayed on pages 624 - 625 in the print version)
 1   import   java.io.*; 2 3   public class   FixedLengthStringIO { 4  /** Read fixed number of characters from a DataInput stream */  5   public static   String readFixedLengthString(   int   size, 6 DataInput in)   throws   IOException { 7  // Declare an array of characters  8   char   [] chars =   new char   [size]; 9 10  // Read fixed number of characters to the array  11   for   (   int   i =     ; i < size; i++) 12 chars[i] = in.readChar(); 13 

[Page 625]
 14   return new   String(chars); 15 } 16 17  /** Write fixed number of characters to a DataOutput stream */  18   public static void   writeFixedLengthString(String s,   int   size, 19 DataOutput out)   throws   IOException { 20   char   [] chars =   new char   [size]; 21 22  // Fill in string with characters  23 s.getChars(     ,  Math.min(s.length(), size)  , chars,     ); 24 25  // Fill in blank characters in the rest of the array  26   for   (   int   i =  Math.min(s.length(), size)  ; i < chars.length; i++) 27 chars[i] =   ' '   ; 28 29  // Create and write a new string padded with blank characters  30 out.writeChars(   new   String(chars)); 31 } 32 } 

The writeFixedLengthString(String s, int size, DataOutput out) method writes a string in a fixed size to a DataOutput stream. If the string is longer than the specified size, it is truncated (line 23); if it is shorter than the specified size, blanks are padded into it (lines 26 “27). In any case, a new fixed-length string is written to a specified output stream. Since RandomAccessFile implements DataOutput , this method can be used to write a string to a RandomAccessFile . For example, invoking writeFixedLengthString("John", 2, raf) actually writes "Jo" to the RandomAccessFile raf , since the size is 2 . Invoking writeFixedLengthString("John", 6, raf) actually writes "John" to the RandomAccessFile raf , since the size is 6 .

The readFixedLengthString(int size, InputOutput in) method reads a fixed number of characters from an InputStream and returns as a string. Since RandomAccessFile implements InputOutput , this method can be used to read a string from a writeFixedLengthString(String s, int size, DataOutput out) .

The rest of the work can be summarized in the following steps:

1.
Create the user interface.

2.
Add a record to the file.

3.
Read a record from the file.

4.
Write the code to implement the button actions.

The program is shown in Listing 18.9.

Listing 18.9. AddressBook.java
(This item is displayed on pages 625 - 629 in the print version)
 1   import   java.io.*; 2   import   java.awt.*; 3   import   java.awt.event.*; 4   import   javax.swing.*; 5   import   javax.swing.border.*; 6 7   public class   AddressBook   extends   JFrame { 8  // Specify the size of five string fields in the record  9  final static int NAME_SIZE =   32   ;  10   final static int   STREET_SIZE =   32   ; 11   final static int   CITY_SIZE =   20   ; 12   final static int   STATE_SIZE =   2   ; 13   final static int   ZIP_SIZE =   5   ; 

[Page 626]
 14   final static int   RECORD_SIZE = 15 (NAME_SIZE + STREET_SIZE + CITY_SIZE + STATE_SIZE + ZIP_SIZE); 16 17  // Access address.dat using RandomAccessFile  18    private   RandomAccessFile raf;  19 20  // Text fields  21   private   JTextField jtfName =   new   JTextField(NAME_SIZE); 22   private   JTextField jtfStreet =   new   JTextField(STREET_SIZE); 23   private   JTextField jtfCity =   new   JTextField(CITY_SIZE); 24   private   JTextField jtfState =   new   JTextField(STATE_SIZE); 25   private   JTextField jtfZip =   new   JTextField(ZIP_SIZE); 26 27  // Buttons  28   private   JButton jbtAdd =   new   JButton(   "Add"   ); 29   private   JButton jbtFirst =   new   JButton(   "First"   ); 30   private   JButton jbtNext =   new   JButton(   "Next"   ); 31   private   JButton jbtPrevious =   new   JButton(   "Previous"   ); 32   private   JButton jbtLast =   new   JButton(   "Last"   ); 33 34   public   AddressBook() { 35  // Open or create a random access file  36   try   { 37  raf =   new   RandomAccessFile(   "address.dat"   ,   "rw"   );  38 } 39   catch   (IOException ex) { 40 System.out.print(   "Error: "   + ex); 41 System.exit(     ); 42 } 43 44  // Panel p1 for holding labels Name, Street, and City  45 JPanel p1 =   new   JPanel(); 46 p1.setLayout(   new   GridLayout(   3   ,   1   )); 47 p1.add(   new   JLabel(   "Name"   )); 48 p1.add(   new   JLabel(   "Street"   )); 49 p1.add(   new   JLabel(   "City"   )); 50 51  // Panel jpState for holding state  52 JPanel jpState =   new   JPanel(); 53 jpState.setLayout(   new   BorderLayout()); 54 jpState.add(   new   JLabel(   "State"   ), BorderLayout.WEST); 55 jpState.add(jtfState, BorderLayout.CENTER); 56 57  // Panel jpZip for holding zip  58 JPanel jpZip =   new   JPanel(); 59 jpZip.setLayout(   new   BorderLayout()); 60 jpZip.add(   new   JLabel(   "Zip"   ), BorderLayout.WEST); 61 jpZip.add(jtfZip, BorderLayout.CENTER); 62 63  // Panel p2 for holding jpState and jpZip  64 JPanel p2 =   new   JPanel(); 65 p2.setLayout(   new   BorderLayout()); 66 p2.add(jpState, BorderLayout.WEST); 67 p2.add(jpZip, BorderLayout.CENTER); 68 69  // Panel p3 for holding jtfCity and p2  70 JPanel p3 =   new   JPanel(); 71 p3.setLayout(   new   BorderLayout()); 72 p3.add(jtfCity, BorderLayout.CENTER); 73 p3.add(p2, BorderLayout.EAST); 74 

[Page 627]
 75  // Panel p4 for holding jtfName, jtfStreet, and p3  76 JPanel p4 =   new   JPanel(); 77 p4.setLayout(   new   GridLayout(   3   ,   1   )); 78 p4.add(jtfName); 79 p4.add(jtfStreet); 80 p4.add(p3); 81 82  // Place p1 and p4 into jpAddress  83 JPanel jpAddress =   new   JPanel(   new   BorderLayout()); 84 jpAddress.add(p1, BorderLayout.WEST); 85 jpAddress.add(p4, BorderLayout.CENTER); 86 87  // Set the panel with line border  88 jpAddress.setBorder(   new   BevelBorder(BevelBorder.RAISED)); 89 90  // Add buttons to a panel  91 JPanel jpButton =   new   JPanel(); 92 jpButton.add(jbtAdd); 93 jpButton.add(jbtFirst); 94 jpButton.add(jbtNext); 95 jpButton.add(jbtPrevious); 96 jpButton.add(jbtLast); 97 98  // Add jpAddress and jpButton to the frame  99 add(jpAddress, BorderLayout.CENTER); 100 add(jpButton, BorderLayout.SOUTH); 101 102  jbtAdd.addActionListener(   new   ActionListener() {  103   public void   actionPerformed(ActionEvent e) { 104 writeAddress(); 105 } 106 }); 107 jbtFirst.addActionListener(   new   ActionListener() { 108   public void   actionPerformed(ActionEvent e) { 109   try   { 110   if   (raf.length() >     ) readAddress(     ); 111 } 112   catch   (IOException ex) { 113 ex.printStackTrace(); 114 } 115 } 116 }); 117 jbtNext.addActionListener(   new   ActionListener() { 118   public void   actionPerformed(ActionEvent e) { 119   try   { 120   long   currentPosition = raf.getFilePointer(); 121   if   (currentPosition < raf.length()) 122 readAddress(currentPosition); 123 } 124   catch   (IOException ex) { 125 ex.printStackTrace(); 126 } 127 } 128 }); 129 jbtPrevious.addActionListener(   new   ActionListener() { 130   public void   actionPerformed(ActionEvent e) { 131   try   { 132   long   currentPosition = raf.getFilePointer(); 133   if   (currentPosition -   2   * RECORD_SIZE >     ) 134  // Why 2 * 2 * RECORD_SIZE? See the follow-up remarks  135 readAddress(currentPosition -   2   *   2   * RECORD_SIZE); 

[Page 628]
 136   else   137 readAddress(     ); 138 } 139   catch   (IOException ex) { 140 ex.printStackTrace(); 141 } 142 } 143 }); 144 jbtLast.addActionListener(   new   ActionListener() { 145   public void   actionPerformed(ActionEvent e) { 146   try   { 147   long   lastPosition = raf.length(); 148   if   (lastPosition >     ) 149  // Why 2 * RECORD_SIZE? See the follow-up remarks  150 readAddress(lastPosition -   2   * RECORD_SIZE); 151 } 152   catch   (IOException ex) { 153 ex.printStackTrace(); 154 } 155 } 156 }); 157 158  // Display the first record if exists  159   try   { 160   if   (raf.length() >     ) readAddress(     ); 161 } 162   catch   (IOException ex) { 163 ex.printStackTrace(); 164 } 165 } 166 167  /** Write a record at the end of the file */  168    public void   writeAddress() {  169   try   { 170 raf.seek(raf.length()); 171 FixedLengthStringIO.writeFixedLengthString( 172 jtfName.getText(), NAME_SIZE, raf); 173 FixedLengthStringIO.writeFixedLengthString( 174 jtfStreet.getText(), STREET_SIZE, raf); 175 FixedLengthStringIO.writeFixedLengthString( 176 jtfCity.getText(), CITY_SIZE, raf); 177 FixedLengthStringIO.writeFixedLengthString( 178 jtfState.getText(), STATE_SIZE, raf); 179 FixedLengthStringIO.writeFixedLengthString( 180 jtfZip.getText(), ZIP_SIZE, raf); 181 } 182   catch   (IOException ex) { 183 ex.printStackTrace(); 184 } 185 } 186 187  /** Read a record at the specified position */  188    public void   readAddress(   long   position)   throws   IOException {  189 raf.seek(position); 190 string name = FixedLengthStringIO.readFixedLengthString( 191 NAME_SIZE, raf); 192 String street = FixedLengthStringIO.readFixedLengthString( 193 STREET_SIZE, raf); 

[Page 629]
 194 String city = FixedLengthStringIO.readFixedLengthString( 195 CITY_SIZE, raf); 196 String state = FixedLengthStringIO.readFixedLengthString( 197 STATE_SIZE, raf); 198 String zip = FixedLengthStringIO.readFixedLengthString( 199 ZIP_SIZE, raf); 200 201 jtfName.setText(name); 202 jtfStreet.setText(street); 203 jtfCity.setText(city); 204 jtfState.setText(state); 205 jtfZip.setText(zip); 206 } 207 208   public static void   main(String[] args) { 209 AddressBook frame =   new   AddressBook(); 210 frame.pack(); 211 frame.setTitle(   "AddressBook"   ); 212 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 213 frame.setVisible(   true   ); 214 } 215 } 

  • A random access file, address.dat , is created to store address information if the file does not yet exist (line 37). If it already exists, the file is opened. A random file object, raf , is used for both write and read operations. The size of each field in the record is fixed and therefore defined as a constant in lines 9 “15.

  • The user interface is created in lines 44 “100. The listeners are registered in lines 102 “156. When the program starts, it displays the first record, if it exists, in lines 159 “164.

  • The writeAddress() method sets the file pointer to the end of the file (line 170) and writes a new record to the file (lines 171 “180).

  • The readAddress() method sets the file pointer at the specified position (line 189) and reads a record from the file (lines 190 “199). The record is displayed in lines 201 “205.

  • To add a record, you need to collect the address information from the user interface and write the address into the file (line 104).

  • The code to process button events is implemented in lines 102 “156. For the First button, read the record from position (line 110). For the Next button, read the record from the current file pointer (line 122). When a record is read, the file pointer is moved 2 * RECORD_SIZE number of bytes ahead of the previous file pointer. For the Previous button, you need to display the record prior to the one being displayed now. So you have to move the file pointer two records before the current file pointer (line 135). For the Last button, read the record from the position at raf.length() - 2 * RECORD_SIZE .

 


Introduction to Java Programming-Comprehensive Version
Introduction to Java Programming-Comprehensive Version (6th Edition)
ISBN: B000ONFLUM
EAN: N/A
Year: 2004
Pages: 503

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net