14.10. Case Study: A Transaction-Processing Program

We now present a substantial transaction-processing program (Fig. 14.14) using a random-access file to achieve instant-access processing. The program maintains a bank’s account information. It updates existing accounts, adds new accounts, deletes accounts and stores a formatted listing of all current accounts in a text file. We assume that the program of Fig. 14.11 has been executed to create the file credit.dat and that the program of Fig. 14.12 has been executed to insert the initial data. Line 25 opens the credit.dat file by creating an fstream object for both reading and writing in binary format.


 1   // Fig. 14.14: Fig14_14.cpp
 2   // This program reads a random-access file sequentially, updates
 3   // data previously written to the file, creates data to be placed
 4   // in the file, and deletes data previously stored in the file.
 5   #include <iostream>
 6   #include <fstream>  
 7   #include <iomanip>
 8   #include <cstdlib>
 9   #include "ClientData.h" // ClientData class definition
10   using namespace std;
11
12   int enterChoice();
13   void createTextFile( fstream& );
14   void updateRecord( fstream& );
15   void newRecord( fstream& );
16   void deleteRecord( fstream& );
17   void outputLine( ostream&, const ClientData & );
18   int getAccount( const char * const );
19
20   enum Choices { PRINT = 1, UPDATE, NEW, DELETE, END };
21
22   int main()
23   {
24      // open file for reading and writing                                  
25      fstream inOutCredit( "credit.dat", ios::in | ios::out | ios::binary );
26
27      // exit program if fstream cannot open file
28      if ( !inOutCredit )
29      {
30         cerr << "File could not be opened." << endl;
31         exit ( EXIT_FAILURE );
32      } // end if
33
34      int choice; // store user choice
35
36      // enable user to specify action
37      while ( ( choice = enterChoice() ) != END )
38      {
39         switch ( choice )
40         {
41            case PRINT: // create text file from record file
42               createTextFile( inOutCredit );
43               break;
44            case UPDATE: // update record
45               updateRecord( inOutCredit );
46               break;
47            case NEW: // create record
48               newRecord( inOutCredit );
49               break;
50            case DELETE: // delete existing record
51               deleteRecord( inOutCredit );
52               break;
53            default: // display error if user does not select valid choice
54               cerr << "Incorrect choice" << endl;
55               break;
56         } // end switch
57
58         inOutCredit.clear(); // reset end-of-file indicator
59      } // end while
60   } // end main
61
62   // enable user to input menu choice
63   int enterChoice()
64   {
65      // display available options
66      cout << " Enter your choice" << endl
67         << "1 - store a formatted text file of accounts" << endl
68         << "    called "print.txt" for printing" << endl
69         << "2 - update an account" << endl
70         << "3 - add a new account" << endl
71         << "4 - delete an account" << endl
72         << "5 - end program ? ";
73
74      int menuChoice;
75      cin >> menuChoice; // input menu selection from user
76      return menuChoice;
77   } // end function enterChoice
78
79   // create formatted text file for printing
80   void createTextFile( fstream &readFromFile )
81   {
82      // create text file                            
83      ofstream outPrintFile( "print.txt", ios::out );
84
85      // exit program if ofstream cannot create file
86      if ( !outPrintFile )
87      {
88         cerr << "File could not be created." << endl;
89         exit( EXIT_FAILURE );
90      } // end if
91
92      // output column heads
93      outPrintFile << left << setw( 10 ) << "Account" << setw( 16 )
94         << "Last Name" << setw( 11 ) << "First Name" << right     
95         << setw( 10 ) << "Balance" << endl;                       
96
97      // set file-position pointer to beginning of readFromFile
98      readFromFile.seekg( 0 );                                 
99
100     // read first record from record file
101     ClientData client;
102     readFromFile.read( reinterpret_cast< char * >( &client ),
103        sizeof( ClientData ) );                               
104
105     // copy all records from record file into text file
106     while ( !readFromFile.eof() )
107     {
108        // write single record to text file
109        if ( client.getAccountNumber() != 0 ) // skip empty records
110           outputLine( outPrintFile, client );
111
112        // read next record from record file                     
113        readFromFile.read( reinterpret_cast< char * >( &client ),
114           sizeof( ClientData ) );                               
115     } // end while
116  } // end function createTextFile
117
118  // update balance in record
119  void updateRecord( fstream &updateFile )
120  {
121     // obtain number of account to update
122     int accountNumber = getAccount( "Enter account to update" );
123
124     // move file-position pointer to correct record in file          
125     updateFile.seekg( ( accountNumber - 1 ) * sizeof( ClientData ) );
126
127     // read first record from file
128     ClientData client;
129     updateFile.read( reinterpret_cast< char * >( &client ),
130        sizeof( ClientData ) );                             
131
132     // update record
133     if ( client.getAccountNumber() != 0 )
134     {
135        outputLine( cout, client ); // display the record
136
137        // request user to specify transaction
138        cout << " Enter charge (+) or payment (-): ";
139        double transaction; // charge or payment
140        cin >> transaction;
141
142        // update record balance
143        double oldBalance = client.getBalance();
144        client.setBalance( oldBalance + transaction );
145        outputLine( cout, client ); // display the record
146
147        // move file-position pointer to correct record in file          
148        updateFile.seekp( ( accountNumber - 1 ) * sizeof( ClientData ) );
149
150        // write updated record over old record in file               
151        updateFile.write( reinterpret_cast< const char * >( &client ),
152           sizeof( ClientData ) );                                    
153     } // end if
154     else // display error if account does not exist
155        cerr << "Account #" << accountNumber
156           << " has no information." << endl;
157  } // end function updateRecord
158
159  // create and insert record
160  void newRecord( fstream &insertInFile )
161  {
162     // obtain number of account to create
163     int accountNumber = getAccount( "Enter new account number" );
164
165     // move file-position pointer to correct record in file
166     insertInFile.seekg( ( accountNumber - 1 ) * sizeof( ClientData ) );
167
168     // read record from file
169     ClientData client;
170     insertInFile.read( reinterpret_cast< char * >( &client ),
171        sizeof( ClientData ) );                               
172
173     // create record, if record does not previously exist
174     if ( client.getAccountNumber() == 0 )
175     {
176        string lastName;
177        string firstName;
178        double balance;
179
180        // user enters last name, first name and balance
181        cout << "Enter lastname, firstname, balance ? ";
182        cin >> setw( 15 ) >> lastName;
183        cin >> setw( 10 ) >> firstName;
184        cin >> balance;
185
186        // use values to populate account values
187        client.setLastName( lastName );
188        client.setFirstName( firstName );
189        client.setBalance( balance );
190        client.setAccountNumber( accountNumber );
191
192        // move file-position pointer to correct record in file            
193        insertInFile.seekp( ( accountNumber - 1 ) * sizeof( ClientData ) );
194
195        // insert record in file                                        
196        insertInFile.write( reinterpret_cast< const char * >( &client ),
197           sizeof( ClientData ) );                                      
198     } // end if
199     else // display error if account already exists
200        cerr << "Account #" << accountNumber
201           << " already contains information." << endl;
202  } // end function newRecord
203
204  // delete an existing record
205  void deleteRecord( fstream &deleteFromFile )
206  {
207     // obtain number of account to delete
208     int accountNumber = getAccount( "Enter account to delete" );
209
210     // move file-position pointer to correct record in file              
211     deleteFromFile.seekg( ( accountNumber - 1 ) * sizeof( ClientData ) );
212
213     // read record from file
214     ClientData client;
215     deleteFromFile.read( reinterpret_cast< char * >( &client ),
216        sizeof( ClientData ) );                                 
217
218     // delete record, if record exists in file
219     if ( client.getAccountNumber() != 0 )
220     {
221        ClientData blankClient; // create blank record
222
223        // move file-position pointer to correct record in file
224        deleteFromFile.seekp( ( accountNumber - 1 ) *          
225           sizeof( ClientData ) );                             
226
227        // replace existing record with blank record        
228        deleteFromFile.write(                               
229           reinterpret_cast< const char * >( &blankClient ),
230           sizeof( ClientData ) );                          
231
232        cout << "Account #" << accountNumber << " deleted. ";
233     } // end if
234     else // display error if record does not exist
235        cerr << "Account #" << accountNumber << " is empty. ";
236  } // end deleteRecord
237
238  // display single record
239  void outputLine( ostream &output, const ClientData &record )
240  {
241     output << left << setw( 10 ) << record.getAccountNumber()
242        << setw( 16 ) << record.getLastName()
243        << setw( 11 ) << record.getFirstName()
244        << setw( 10 ) << setprecision( 2 ) << right << fixed
245        << showpoint << record.getBalance() << endl;
246  } // end function outputLine
247
248  // obtain account-number value from user
249  int getAccount( const char * const prompt )
250  {
251     int accountNumber;
252
253     // obtain account-number value
254     do
255     {
256        cout << prompt << " (1 - 100): ";
257        cin >> accountNumber;
258     } while ( accountNumber < 1 || accountNumber > 100 );
259
260     return accountNumber;
261  } // end function getAccount


Fig. 14.14. Bank account program.

The program has five options (Option 5 is for terminating the program). Option 1 calls function createTextFile to store a formatted list of all the account information in a text file called print.txt that may be printed. Function createTextFile (lines 80–116) takes an fstream object as an argument to be used to input data from the credit.dat file. Function createTextFile invokes istream member function read (lines 102–103) and uses the sequential-file-access techniques of Fig. 14.13 to input data from credit.dat. Function outputLine, discussed in Section 14.9, outputs the data to file print.txt. Note that function createTextFile uses istream member function seekg (line 98) to ensure that the file-position pointer is at the beginning of the file. After choosing Option 1, the print.txt file contains

Account   Last Name       First Name    Balance
29        Brown           Nancy          -24.54
33        Dunn            Stacey         314.33
37        Barker          Doug             0.00
88        Smith           Dave           258.34
96        Stone           Sam             34.98

Option 2 calls updateRecord (lines 119–157) to update an account. This function updates only an existing record, so the function first determines whether the specified record is empty. Lines 129–130 read data into object client, using istream member function read. Then line 133 compares the value returned by getAccountNumber of the client object to zero to determine whether the record contains information. If this value is zero, lines 155–156 print an error message indicating that the record is empty. If the record contains information, line 135 displays the record, using function outputLine, line 140 inputs the transaction amount and lines 143–152 calculate the new balance and rewrite the record to the file. A typical execution for Option 2 is

Enter account to update (1 - 100): 37
37        Barker          Doug             0.00

Enter charge (+) or payment (-): +87.99
37        Barker          Doug            87.99

Option 3 calls function newRecord (lines 160–202) to add a new account to the file. If the user enters an account number for an existing account, newRecord displays an error message indicating that the account exists (lines 200–201). This function adds a new account in the same manner as the program of Fig. 14.12. A typical execution for Option 3 is

Enter new account number (1 - 100): 22
Enter lastname, firstname, balance
? Johnston Sarah 247.45

Option 4 calls function deleteRecord (lines 205–236) to delete a record from the file. Line 208 prompts the user to enter the account number. Only an existing record may be deleted, so, if the specified account is empty, line 235 displays an error message. If the account exists, lines 221–230 reinitialize that account by copying an empty record (blankClient) to the file. Line 232 displays a message to inform the user that the record has been deleted. A typical execution for Option 4 is

Enter account to delete (1 - 100): 29
Account #29 deleted.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.15.181.87