Case Study: A Transaction-Processing Program

Case Study A Transaction Processing Program

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.





C++ How to Program
C++ How to Program (5th Edition)
ISBN: 0131857576
EAN: 2147483647
Year: 2004
Pages: 627
Simiral book on Amazon

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