14.11 Case Study: A Transaction-Processing Program

We now present a substantial transaction-processing program (Fig. 14.13) 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.10 has been executed to create the file credit.dat and that the program of Fig. 14.11 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.








Fig. 14.13 Bank-account program.

Alternate View

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

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 76–109) 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 95–96) and uses the sequential-file-access techniques of Fig. 14.12 to input data from credit.dat. Function outputLine, discussed in Section 14.10, outputs the data to file print.txt. Note that function createTextFile uses istream member function seekg (line 91) to ensure that the file-position pointer is at the beginning of the file before reading the file’s contents. 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 112–148) to update an account. This function updates only an existing record, so the function first determines whether the specified record is empty—we use function getAccount (lines 235–245) to read from the user the number of the record to update. Line 121 reads data into object client, using istream member function read. Then line 124 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 145–146 print an error message indicating that the record is empty. If the record contains information, line 125 displays the record, using function outputLine, line 130 inputs the transaction amount and lines 133–142 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 151–192) 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 189–190). This function adds a new account in the same manner as the program of Fig. 14.11. 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 195–223) to delete a record from the file. Line 197 prompts the user to enter the account number. Only an existing record may be deleted, so, if the specified account is empty, line 221 displays an error message. If the account exists, lines 209–216 reinitialize that account by writing an empty record (blank-Client) to the file. Line 218 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