We now present a substantial transaction-processing program (Fig. 17.15) using a random-access file to achieve "instant" access processing. The program maintains a bank's account information. The program 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. 17.12 has been executed to create the file credit.dat and that the program of Fig. 17.13 has been executed to insert the initial data.
Figure 17.15. Bank account program.
(This item is displayed on pages 867 - 872 in the print version)
1 // Fig. 17.15: Fig17_15.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 in the file. 5 #include 6 using std::cerr; 7 using std::cin; 8 using std::cout; 9 using std::endl; 10 using std::fixed; 11 using std::ios; 12 using std::left; 13 using std::right; 14 using std::showpoint; 15 16 #include 17 using std::ofstream; 18 using std::ostream; 19 using std::fstream; 20 21 #include 22 using std::setw; 23 using std::setprecision; 24 25 #include 26 using std::exit; // exit function prototype 27 28 #include "ClientData.h" // ClientData class definition 29 30 int enterChoice(); 31 void createTextFile( fstream& ); 32 void updateRecord( fstream& ); 33 void newRecord( fstream& ); 34 void deleteRecord( fstream& ); 35 void outputLine( ostream&, const ClientData & ); 36 int getAccount( const char * const ); 37 38 enum Choices { PRINT = 1, UPDATE, NEW, DELETE, END }; 39 40 int main() 41 { 42 // open file for reading and writing 43 fstream inOutCredit( "credit.dat", ios::in | ios::out ); 44 45 // exit program if fstream cannot open file 46 if ( !inOutCredit ) 47 { 48 cerr << "File could not be opened." << endl; 49 exit ( 1 ); 50 } // end if 51 52 int choice; // store user choice 53 54 // enable user to specify action 55 while ( ( choice = enterChoice() ) != END ) 56 { 57 switch ( choice ) 58 { 59 case PRINT: // create text file from record file 60 createTextFile( inOutCredit ); 61 break; 62 case UPDATE: // update record 63 updateRecord( inOutCredit ); 64 break; 65 case NEW: // create record 66 newRecord( inOutCredit ); 67 break; 68 case DELETE: // delete existing record 69 deleteRecord( inOutCredit ); 70 break; 71 default: // display error if user does not select valid choice 72 cerr << "Incorrect choice" << endl; 73 break; 74 } // end switch 75 76 inOutCredit.clear(); // reset end-of-file indicator 77 } // end while 78 79 return 0; 80 } // end main 81 82 // enable user to input menu choice 83 int enterChoice() 84 { 85 // display available options 86 cout << " Enter your choice" << endl 87 << "1 - store a formatted text file of accounts" << endl 88 << " called "print.txt" for printing" << endl 89 << "2 - update an account" << endl 90 << "3 - add a new account" << endl 91 << "4 - delete an account" << endl 92 << "5 - end program ? "; 93 94 int menuChoice; 95 cin >> menuChoice; // input menu selection from user 96 return menuChoice; 97 } // end function enterChoice 98 99 // create formatted text file for printing 100 void createTextFile( fstream &readFromFile ) 101 { 102 // create text file 103 ofstream outPrintFile( "print.txt", ios::out ); 104 105 // exit program if ofstream cannot create file 106 if ( !outPrintFile ) 107 { 108 cerr << "File could not be created." << endl; 109 exit( 1 ); 110 } // end if 111 112 outPrintFile << left << setw( 10 ) << "Account" << setw( 16 ) 113 << "Last Name" << setw( 11 ) << "First Name" << right 114 << setw( 10 ) << "Balance" << endl; 115 116 // set file-position pointer to beginning of readFromFile 117 readFromFile.seekg( 0 ); 118 119 // read first record from record file 120 ClientData client; 121 readFromFile.read( reinterpret_cast< char * >( &client ), 122 sizeof( ClientData ) ); 123 124 // copy all records from record file into text file 125 while ( !readFromFile.eof() ) 126 { 127 // write single record to text file 128 if ( client.getAccountNumber() != 0 ) // skip empty records 129 outputLine( outPrintFile, client ); 130 131 // read next record from record file 132 readFromFile.read( reinterpret_cast< char * >( &client ), 133 sizeof( ClientData ) ); 134 } // end while 135 } // end function createTextFile 136 137 // update balance in record 138 void updateRecord( fstream &updateFile ) 139 { 140 // obtain number of account to update 141 int accountNumber = getAccount( "Enter account to update" ); 142 143 // move file-position pointer to correct record in file 144 updateFile.seekg( ( accountNumber - 1 ) * sizeof( ClientData ) ); 145 146 // read first record from file 147 ClientData client; 148 updateFile.read( reinterpret_cast< char * >( &client ), 149 sizeof( ClientData ) ); 150 151 // update record 152 if ( client.getAccountNumber() != 0 ) 153 { 154 outputLine( cout, client ); // display the record 155 156 // request user to specify transaction 157 cout << " Enter charge (+) or payment (-): "; 158 double transaction; // charge or payment 159 cin >> transaction; 160 161 // update record balance 162 double oldBalance = client.getBalance(); 163 client.setBalance( oldBalance + transaction ); 164 outputLine( cout, client ); // display the record 165 166 // move file-position pointer to correct record in file 167 updateFile.seekp( ( accountNumber - 1 ) * sizeof( ClientData ) ); 168 169 // write updated record over old record in file 170 updateFile.write( reinterpret_cast< const char * >( &client ), 171 sizeof( ClientData ) ); 172 } // end if 173 else // display error if account does not exist 174 cerr << "Account #" << accountNumber 175 << " has no information." << endl; 176 } // end function updateRecord 177 178 // create and insert record 179 void newRecord( fstream &insertInFile ) 180 { 181 // obtain number of account to create 182 int accountNumber = getAccount( "Enter new account number" ); 183 184 // move file-position pointer to correct record in file 185 insertInFile.seekg( ( accountNumber - 1 ) * sizeof( ClientData ) ); 186 187 // read record from file 188 ClientData client; 189 insertInFile.read( reinterpret_cast< char * >( &client ), 190 sizeof( ClientData ) ); 191 192 // create record, if record does not previously exist 193 if ( client.getAccountNumber() == 0 ) 194 { 195 char lastName[ 15 ]; 196 char firstName[ 10 ]; 197 double balance; 198 199 // user enters last name, first name and balance 200 cout << "Enter lastname, firstname, balance ? "; 201 cin >> setw( 15 ) >> lastName; 202 cin >> setw( 10 ) >> firstName; 203 cin >> balance; 204 205 // use values to populate account values 206 client.setLastName( lastName ); 207 client.setFirstName( firstName ); 208 client.setBalance( balance ); 209 client.setAccountNumber( accountNumber ); 210 211 // move file-position pointer to correct record in file 212 insertInFile.seekp( ( accountNumber - 1 ) * sizeof( ClientData ) ); 213 214 // insert record in file 215 insertInFile.write( reinterpret_cast< const char * >( &client ), 216 sizeof( ClientData ) ); 217 } // end if 218 else // display error if account already exists 219 cerr << "Account #" << accountNumber 220 << " already contains information." << endl; 221 } // end function newRecord 222 223 // delete an existing record 224 void deleteRecord( fstream &deleteFromFile ) 225 { 226 // obtain number of account to delete 227 int accountNumber = getAccount( "Enter account to delete" ); 228 229 // move file-position pointer to correct record in file 230 deleteFromFile.seekg( ( accountNumber - 1 ) * sizeof(ClientData ) ); 231 232 // read record from file 233 ClientData client; 234 deleteFromFile.read( reinterpret_cast< char * >( &client ), 235 sizeof( ClientData ) ); 236 237 // delete record, if record exists in file 238 if ( client.getAccountNumber() != 0 ) 239 { 240 ClientData blankClient; // create blank record 241 242 // move file-position pointer to correct record in file 243 deleteFromFile.seekp( ( accountNumber - 1 ) * 244 sizeof( ClientData ) ); 245 246 // replace existing record with blank record 247 deleteFromFile.write( 248 reinterpret_cast< const char * >( &blankClient ), 249 sizeof( ClientData ) ); 250 251 cout << "Account #" << accountNumber << " deleted. "; 252 } // end if 253 else // display error if record does not exist 254 cerr << "Account #" << accountNumber << " is empty. "; 255 } // end deleteRecord 256 257 // display single record 258 void outputLine( ostream &output, const ClientData &record ) 259 { 260 output << left << setw( 10 ) << record.getAccountNumber() 261 << setw( 16 ) << record.getLastName() 262 << setw( 11 ) << record.getFirstName() 263 << setw( 10 ) << setprecision( 2 ) << right << fixed 264 << showpoint << record.getBalance() << endl; 265 } // end function outputLine 266 267 // obtain account-number value from user 268 int getAccount( const char * const prompt ) 269 { 270 int accountNumber; 271 272 // obtain account-number value 273 do 274 { 275 cout << prompt << " (1 - 100): "; 276 cin >> accountNumber; 277 } while ( accountNumber < 1 || accountNumber > 100 ); 278 279 return accountNumber; 280 } // end function getAccount |
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 100135) 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 132133) and uses the sequential-file-access techniques of Fig. 17.14 to input data from credit.dat. Function outputLine, discussed in Section 17.10, is used to output the data to file print.txt. Note that createTextFile uses istream member function seekg (line 117) 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 138176) to update an account. This function updates only an existing record, so the function first determines whether the specified record is empty. Lines 148149 read data into object client, using istream member function read. Then line 152 compares the value returned by getAccountNumber of the client structure to zero to determine whether the record contains information. If this value is zero, lines 174175 print an error message indicating that the record is empty. If the record contains information, line 154 displays the record, using function outputLine, line 159 inputs the transaction amount and lines 162171 calculate the new balance and rewrite the record to the file. A typical output 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 179221) 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 219220). This function adds a new account in the same manner as the program of Fig. 17.12. A typical output 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 224255) to delete a record from the file. Line 227 prompts the user to enter the account number. Only an existing record may be deleted, so, if the specified account is empty, line 254 displays an error message. If the account exists, lines 247249 reinitialize that account by copying an empty record (blankClient) to the file. Line 251 displays a message to inform the user that the record has been deleted. A typical output for Option 4 is
Enter account to delete (1 - 100): 29 Account #29 deleted. |
Note that line 43 opens the credit.dat file by creating an fstream object for both reading and writing, using modes ios::in and ios::out "or-ed" together.
Introduction to Computers, the Internet and World Wide Web
Introduction to C++ Programming
Introduction to Classes and Objects
Control Statements: Part 1
Control Statements: Part 2
Functions and an Introduction to Recursion
Arrays and Vectors
Pointers and Pointer-Based Strings
Classes: A Deeper Look, Part 1
Classes: A Deeper Look, Part 2
Operator Overloading; String and Array Objects
Object-Oriented Programming: Inheritance
Object-Oriented Programming: Polymorphism
Templates
Stream Input/Output
Exception Handling
File Processing
Class string and String Stream Processing
Web Programming
Searching and Sorting
Data Structures
Bits, Characters, C-Strings and structs
Standard Template Library (STL)
Other Topics
Appendix A. Operator Precedence and Associativity Chart
Appendix B. ASCII Character Set
Appendix C. Fundamental Types
Appendix D. Number Systems
Appendix E. C Legacy Code Topics
Appendix F. Preprocessor
Appendix G. ATM Case Study Code
Appendix H. UML 2: Additional Diagram Types
Appendix I. C++ Internet and Web Resources
Appendix J. Introduction to XHTML
Appendix K. XHTML Special Characters
Appendix L. Using the Visual Studio .NET Debugger
Appendix M. Using the GNU C++ Debugger
Bibliography