1
File Processing Outline 14.1 14.2 14.3 14.4 14.5 14.6 14.7 14.8 14.9 14.10 14.11 14.12
Introduction The Data Hierarchy Files and Streams Creating a Sequential-Access File Reading Data from a Sequential-Access File Updating Sequential-Access Files Random-Access Files Creating a Random-Access File Writing Data Randomly to a Random-Access File Reading Data Sequentially from a Random-Access File Example: A Transaction-Processing Program Input/Output of Objects
© 2003 Prentice Hall, Inc. All rights reserved.
2
14.1 Introduction • Storage of data – Arrays, variables are temporary – Files are permanent • Magnetic disk, optical disk, tapes
• In this chapter – Create, update, process files – Sequential and random access – Formatted and raw processing
© 2003 Prentice Hall, Inc. All rights reserved.
3
14.2 The Data Hierarchy • From smallest to largest – Bit (binary digit) • • • •
1 or 0 Everything in computer ultimately represented as bits Cumbersome for humans to use Character set – Digits, letters, symbols used to represent data – Every character represented by 1's and 0's
– Byte: 8 bits • Can store a character (char) • Also Unicode for large character sets (wchar_t)
© 2003 Prentice Hall, Inc. All rights reserved.
4
14.2 The Data Hierarchy • From smallest to largest (continued) – Field: group of characters with some meaning • Your name
– Record: group of related fields • struct or class in C++ • In payroll system, could be name, SS#, address, wage • Each field associated with same employee • Record key: field used to uniquely identify record
– File: group of related records • Payroll for entire company • Sequential file: records stored by key
– Database: group of related files • Payroll, accounts-receivable, inventory… © 2003 Prentice Hall, Inc. All rights reserved.
5
14.2 The Data Hierarchy
Sally Tom Judy Iris Randy
Judy
Black Blue Green Orange Red
Green
Judy
Field
01001010 Byte (ASCII character J) 1 Bit
© 2003 Prentice Hall, Inc. All rights reserved.
File
Record
6
14.3 Files and Streams • C++ views file as sequence of bytes – Ends with end-of-file marker 0
1
2
3
4
5
6
7
8
9
... ...
n-1 end-of-file marker
• When file opened – Object created, stream associated with it – cin, cout, etc. created when included • Communication between program and file/device
© 2003 Prentice Hall, Inc. All rights reserved.
7
14.3 Files and Streams • To perform file processing – Include and – Class templates • basic_ifstream (input) • basic_ofstream (output) • basic_fstream (I/O)
– typedefs for specializations that allow char I/O • ifstream (char input) • ofstream (char output) • fstream (char I/O)
© 2003 Prentice Hall, Inc. All rights reserved.
8
14.3 Files and Streams • Opening files – Create objects from template – Derive from stream classes • Can use stream methods from Ch. 12 • put, get, peek, etc. basic_ios
basic_istream
basic_ifstream
basic_ostream
basic_iostream
basic_fstream
© 2003 Prentice Hall, Inc. All rights reserved.
basic_ofstream
9
14.4 Creating a Sequential-Access File • C++ imposes no structure on file – Concept of "record" must be implemented by programmer
• To open file, create objects – Creates "line of communication" from object to file – Classes • ifstream (input only) • ofstream (output only) • fstream (I/O)
– Constructors take file name and file-open mode ofstream outClientFile( "filename", fileOpenMode );
– To attach a file later Ofstream outClientFile; outClientFile.open( "filename", fileOpenMode);
© 2003 Prentice Hall, Inc. All rights reserved.
10
14.4 Creating a Sequential-Access File • File-open modes Mode
Description
ios::app
Write all output to the end of the file.
ios::ate
Open a file for output and move to the end of the file (normally used to append data to a file). Data can be written anywhere in the file. Open a file for input. Open a file for output. Discard the file’s contents if it exists (this is also the default action for ios::out)
ios::in ios::out ios::trunc ios::binary
Open a file for binary (i.e., non-text) input or output.
– ofstream opened for output by default • ofstream outClientFile( "clients.dat", ios::out ); • ofstream outClientFile( "clients.dat");
© 2003 Prentice Hall, Inc. All rights reserved.
11
14.4 Creating a Sequential-Access File • Operations – Overloaded operator! • !outClientFile • Returns nonzero (true) if badbit or failbit set – Opened non-existent file for reading, wrong permissions
– Overloaded operator void* • Converts stream object to pointer • 0 when when failbit or badbit set, otherwise nonzero – failbit set when EOF found • while ( cin >> myVariable ) – Implicitly converts cin to pointer – Loops until EOF
© 2003 Prentice Hall, Inc. All rights reserved.
12
14.4 Creating a Sequential-Access File • Operations – Writing to file (just like cout) • outClientFile << myVariable
– Closing file • outClientFile.close() • Automatically closed when destructor called
© 2003 Prentice Hall, Inc. All rights reserved.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
13
// Fig. 14.4: fig14_04.cpp // Create a sequential file. #include using using using using using
Outline fig14_04.cpp (1 of 2)
std::cout; std::cin; std::ios; std::cerr; std::endl;
#include using std::ofstream; #include
Notice the the header files required for file I/O. // exit prototype
int main() { // ofstream constructor opens file ofstream outClientFile( "clients.dat", ios::out ); // exit program if unable to create file if ( !outClientFile ) { // overloaded ! operator cerr << "File could not be opened" << endl; exit( 1 );
ofstream object created and used to open file "clients.dat". If the file does not exist, it is created. ! operator used to test if the file opened properly.
} // end if
© 2003 Prentice Hall, Inc. All rights reserved.
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
14 cout << "Enter the account, name, and balance." << endl << "Enter end-of-file to end input.\n? "; int account; char name[ 30 ]; double balance;
cin is implicitly converted to a pointer. When EOF is encountered, it returns 0 and the loop stops.
Outline fig14_04.cpp (2 of 2)
// read account, name and balance from cin, then place in file while ( cin >> account >> name >> balance ) { outClientFile << account << ' ' << name << ' ' << balance << endl; cout << "? "; } // end while return 0; } // end main
Write data to file like a regular stream.
// ofstream destructor closes file
File closed when destructor called for object. Can be explicitly closed with close().
© 2003 Prentice Hall, Inc. All rights reserved.
Enter Enter ? 100 ? 200 ? 300 ? 400 ? 500 ? ^Z
the account, name, and balance. end-of-file to end input. Jones 24.98 Doe 345.67 White 0.00 Stone -42.16 Rich 224.62
15
Outline fig14_04.cpp output (1 of 1)
© 2003 Prentice Hall, Inc. All rights reserved.
16
14.5 Reading Data from a SequentialAccess File • Reading files – ifstream inClientFile( "filename", ios::in );
– Overloaded ! • !inClientFile tests if file was opened properly
– operator void* converts to pointer • while (inClientFile >> myVariable) • Stops when EOF found (gets value 0)
© 2003 Prentice Hall, Inc. All rights reserved.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
// Fig. 14.7: fig14_07.cpp // Reading and printing a sequential file. #include using using using using using using using using using
std::cout; std::cin; std::ios; std::cerr; std::endl; std::left; std::right; std::fixed; std::showpoint;
17
Outline fig14_07.cpp (1 of 3)
#include using std::ifstream; #include using std::setw; using std::setprecision; #include // exit prototype void outputLine( int, const char * const, double );
© 2003 Prentice Hall, Inc. All rights reserved.
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
int main() { // ifstream constructor opens the file ifstream inClientFile( "clients.dat", ios::in ); // exit program if ifstream could not open file if ( !inClientFile ) { cerr << "File could not be opened" << endl; exit( 1 );
18
Outline Open and test file for input. fig14_07.cpp (2 of 3)
} // end if int account; char name[ 30 ]; double balance; cout << left << setw( 10 ) << "Account" << setw( 13 ) Read from<
found. // display each record in file while ( inClientFile >> account >> name >> balance ) outputLine( account, name, balance ); return 0; // ifstream destructor closes the file } // end main
© 2003 Prentice Hall, Inc. All rights reserved.
54 55 56 57 58 59 60 61 62 63
19 // display single record from file void outputLine( int account, const char * const name, double balance ) { cout << left << setw( 10 ) << account << setw( 13 ) << name << setw( 7 ) << setprecision( 2 ) << right << balance << endl;
Outline fig14_07.cpp (3 of 3) fig14_07.cpp output (1 of 1)
} // end function outputLine
Account 100 200 300 400 500
Name Jones Doe White Stone Rich
Balance 24.98 345.67 0.00 -42.16 224.62
© 2003 Prentice Hall, Inc. All rights reserved.
20
14.5 Reading Data from a SequentialAccess File • File position pointers – Number of next byte to read/write – Functions to reposition pointer • seekg (seek get for istream class) • seekp (seek put for ostream class) • Classes have "get" and "put" pointers
– seekg and seekp take offset and direction • Offset: number of bytes relative to direction • Direction (ios::beg default) – ios::beg - relative to beginning of stream – ios::cur - relative to current position – ios::end - relative to end
© 2003 Prentice Hall, Inc. All rights reserved.
21
14.5 Reading Data from a SequentialAccess File • Examples – fileObject.seekg(0) • Goes to front of file (location 0) because ios::beg is default
– fileObject.seekg(n) • Goes to nth byte from beginning
– fileObject.seekg(n, ios::cur) • Goes n bytes forward
– fileObject.seekg(y, ios::end) • Goes y bytes back from end
– fileObject.seekg(0, ios::cur) • Goes to last byte
– seekp similar © 2003 Prentice Hall, Inc. All rights reserved.
22
14.5 Reading Data from a SequentialAccess File • To find pointer location – tellg and tellp – location = fileObject.tellg()
• Upcoming example – Credit manager program – List accounts with zero balance, credit, and debit
© 2003 Prentice Hall, Inc. All rights reserved.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
// Fig. 14.8: fig14_08.cpp // Credit-inquiry program. #include using using using using using using using using using
std::cout; std::cin; std::ios; std::cerr; std::endl; std::fixed; std::showpoint; std::left; std::right;
23
Outline fig14_08.cpp (1 of 6)
#include using std::ifstream; #include using std::setw; using std::setprecision; #include
© 2003 Prentice Hall, Inc. All rights reserved.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
enum RequestType { ZERO_BALANCE = 1, CREDIT_BALANCE, DEBIT_BALANCE, END }; int getRequest(); bool shouldDisplay( int, double ); void outputLine( int, const char * const, double );
24
Outline fig14_08.cpp (2 of 6)
int main() { // ifstream constructor opens the file ifstream inClientFile( "clients.dat", ios::in ); // exit program if ifstream could not open file if ( !inClientFile ) { cerr << "File could not be opened" << endl; exit( 1 ); } // end if int request; int account; char name[ 30 ]; double balance; // get user's request (e.g., zero, credit or debit balance) request = getRequest();
© 2003 Prentice Hall, Inc. All rights reserved.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
// process user's request while ( request != END ) { switch ( request ) { case ZERO_BALANCE: cout << "\nAccounts with zero balances:\n"; break;
25
Outline fig14_08.cpp (3 of 6)
case CREDIT_BALANCE: cout << "\nAccounts with credit balances:\n"; break; case DEBIT_BALANCE: cout << "\nAccounts with debit balances:\n"; break; } // end switch
© 2003 Prentice Hall, Inc. All rights reserved.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
// read account, name and balance from file inClientFile >> account >> name >> balance; // display file contents (until eof) while ( !inClientFile.eof() ) {
26
Outline fig14_08.cpp (4 of 6)
// display record if ( shouldDisplay( request, balance ) ) outputLine( account, name, balance ); // read account, name and balance from file inClientFile >> account >> name >> balance; } // end inner while
Use clear to reset eof. Use seekg to set file position pointer to beginning of file.
inClientFile.clear(); // reset eof for next input inClientFile.seekg( 0 ); // move to beginning of file request = getRequest(); // get additional request from user } // end outer while cout << "End of run." << endl; return 0; // ifstream destructor closes the file } // end main
© 2003 Prentice Hall, Inc. All rights reserved.
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
27 // obtain request from user int getRequest() { int request;
Outline fig14_08.cpp (5 of 6)
// display request options cout << "\nEnter request" << endl << " 1 - List accounts with zero balances" << endl << " 2 - List accounts with credit balances" << endl << " 3 - List accounts with debit balances" << endl << " 4 - End of run" << fixed << showpoint; // input user request do { cout << "\n? "; cin >> request; } while ( request < ZERO_BALANCE && request > END ); return request; } // end function getRequest
© 2003 Prentice Hall, Inc. All rights reserved.
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
// determine whether to display given record bool shouldDisplay( int type, double balance ) { // determine whether to display credit balances if ( type == CREDIT_BALANCE && balance < 0 ) return true;
28
Outline fig14_08.cpp (6 of 6)
// determine whether to display debit balances if ( type == DEBIT_BALANCE && balance > 0 ) return true; // determine whether to display zero balances if ( type == ZERO_BALANCE && balance == 0 ) return true; return false; } // end function shouldDisplay // display single record from file void outputLine( int account, const char * const name, double balance ) { cout << left << setw( 10 ) << account << setw( 13 ) << name << setw( 7 ) << setprecision( 2 ) << right << balance << endl; } // end function outputLine
© 2003 Prentice Hall, Inc. All rights reserved.
Enter request 1 - List accounts with zero balances 2 - List accounts with credit balances 3 - List accounts with debit balances 4 - End of run ? 1
29
Outline fig14_08.cpp output (1 of 2)
Accounts with zero balances: 300 White 0.00 Enter request 1 - List accounts with zero balances 2 - List accounts with credit balances 3 - List accounts with debit balances 4 - End of run ? 2 Accounts with credit balances: 400 Stone -42.16
© 2003 Prentice Hall, Inc. All rights reserved.
Enter request 1 - List accounts with zero balances 2 - List accounts with credit balances 3 - List accounts with debit balances 4 - End of run ? 3
30
Outline fig14_08.cpp output (2 of 2)
Accounts with debit balances: 100 Jones 24.98 200 Doe 345.67 500 Rich 224.62 Enter request 1 - List accounts with zero balances 2 - List accounts with credit balances 3 - List accounts with debit balances 4 - End of run ? 4 End of run.
© 2003 Prentice Hall, Inc. All rights reserved.
31
14.6 Updating Sequential-Access Files • Updating sequential files – Risk overwriting other data – Example: change name "White" to "Worthington" • Old data 300 White 0.00 400 Jones 32.87
• Insert new data 300 Worthington 0.00 300 White 0.00 400 Jones 32.87
Data gets overwritten 300 Worthington 0.00ones 32.87
– Formatted text different from internal representation – Problem can be avoided, but awkward © 2003 Prentice Hall, Inc. All rights reserved.
32
14.7 Random-Access Files • Instant access – Want to locate record quickly • Airline reservations, ATMs
– Sequential files must search through each one
• Random-access files are solution – Instant access – Insert record without destroying other data – Update/delete items without changing other data
© 2003 Prentice Hall, Inc. All rights reserved.
33
14.7 Random-Access Files • C++ imposes no structure on files – Programmer must create random-access files – Simplest way: fixed-length records • Calculate position in file from record size and key 0
100
200
300
400
500
}
byte offsets
}
}
}
}
}
}
100
100
100
100
100
100
bytes
bytes
bytes
bytes
bytes
bytes
© 2003 Prentice Hall, Inc. All rights reserved.
34
14.8 Creating a Random-Access File • "1234567" (char *) vs 1234567 (int) – char * takes 8 bytes (1 for each character + null) – int takes fixed number of bytes (perhaps 4) • 123 same size in bytes as 1234567
• << operator and write() – outFile << number • Outputs number (int) as a char * • Variable number of bytes
– outFile.write( const char *, size ); • Outputs raw bytes • Takes pointer to memory location, number of bytes to write – Copies data directly from memory into file – Does not convert to char * © 2003 Prentice Hall, Inc. All rights reserved.
35
14.8 Creating a Random-Access File • Example outFile.write( reinterpret_cast(&number), sizeof( number ) );
– &number is an int * • Convert to const char * with reinterpret_cast
– sizeof(number) • Size of number (an int) in bytes
– read function similar (more later) – Must use write/read between compatible machines • Only when using raw, unformatted data
– Use ios::binary for raw writes/reads
© 2003 Prentice Hall, Inc. All rights reserved.
36
14.8 Creating a Random-Access File • Usually write entire struct or object to file • Problem statement – Credit processing program – Store at most 100 fixed-length records – Record • Account number (key) • First and last name • Balance
– Account operations • Update, create new, delete, list all accounts in a file
• Next: program to create blank 100-record file © 2003 Prentice Hall, Inc. All rights reserved.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
// Fig. 14.10: clientData.h // Class ClientData definition used in Fig. 14.12–Fig. 14.15. #ifndef CLIENTDATA_H #define CLIENTDATA_H #include using std::string;
Class ClientData stores the information for each person. 100 blank ClientData objects will be written to a file.
37
Outline clientData.h (1 of 2)
class ClientData { public: // default ClientData constructor ClientData( int = 0, string = "", string = "", double = 0.0 ); // accessor functions for accountNumber void setAccountNumber( int ); int getAccountNumber() const; // accessor functions for lastName void setLastName( string ); string getLastName() const;
© 2003 Prentice Hall, Inc. All rights reserved.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
38
// accessor functions for firstName void setFirstName( string ); string getFirstName() const;
Outline clientData.h (2 of 2)
// accessor functions for balance void setBalance( double ); double getBalance() const; private: int accountNumber; char lastName[ 15 ]; char firstName[ 10 ]; double balance;
Put limits on the size of the first and last name. accountNumber (an int) and balance (double) are already of a fixed size.
}; // end class ClientData #endif
© 2003 Prentice Hall, Inc. All rights reserved.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
// Fig. 14.11: ClientData.cpp // Class ClientData stores customer's credit information. #include using std::string;
39
Outline ClientData.cpp (1 of 4)
#include #include "clientData.h" // default ClientData constructor ClientData::ClientData( int accountNumberValue, string lastNameValue, string firstNameValue, double balanceValue ) { setAccountNumber( accountNumberValue ); setLastName( lastNameValue ); setFirstName( firstNameValue ); setBalance( balanceValue ); } // end ClientData constructor // get account-number value int ClientData::getAccountNumber() const { return accountNumber; } // end function getAccountNumber
© 2003 Prentice Hall, Inc. All rights reserved.
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
40 // set account-number value void ClientData::setAccountNumber( int accountNumberValue ) { accountNumber = accountNumberValue;
Outline ClientData.cpp (2 of 4)
} // end function setAccountNumber // get last-name value string ClientData::getLastName() const { return lastName; } // end function getLastName // set last-name value void ClientData::setLastName( string lastNameString ) { // copy at most 15 characters from string to lastName const char *lastNameValue = lastNameString.data(); int length = strlen( lastNameValue ); length = ( length < 15 ? length : 14 ); strncpy( lastName, lastNameValue, length ); // append null character to lastName lastName[ length ] = '\0';
© 2003 Prentice Hall, Inc. All rights reserved.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
41 } // end function setLastName // get first-name value string ClientData::getFirstName() const { return firstName;
Outline ClientData.cpp (3 of 4)
} // end function getFirstName // set first-name value void ClientData::setFirstName( string firstNameString ) { // copy at most 10 characters from string to firstName const char *firstNameValue = firstNameString.data(); int length = strlen( firstNameValue ); length = ( length < 10 ? length : 9 ); strncpy( firstName, firstNameValue, length ); // append new-line character to firstName firstName[ length ] = '\0'; } // end function setFirstName
© 2003 Prentice Hall, Inc. All rights reserved.
78 79 80 81 82 83 84 85 86 87 88 89 90
// get balance value double ClientData::getBalance() const { return balance; } // end function getBalance
42
Outline ClientData.cpp (4 of 4)
// set balance value void ClientData::setBalance( double balanceValue ) { balance = balanceValue; } // end function setBalance
© 2003 Prentice Hall, Inc. All rights reserved.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
// Fig. 14.12: fig14_12.cpp // Creating a randomly accessed file. #include
43
Outline fig14_12.cpp (1 of 2)
using std::cerr; using std::endl; using std::ios; #include using std::ofstream; #include #include "clientData.h"
// ClientData class definition
int main() { ofstream outCredit( "credit.dat", ios::binary );
Open a file for raw writing using an ofstream object and ios::binary.
// exit program if ofstream could not open file if ( !outCredit ) { cerr << "File could not be opened." << endl; exit( 1 ); } // end if
© 2003 Prentice Hall, Inc. All rights reserved.
26 27 28 29 30 31 32 33 34 35 36 37 38
44 // create ClientData with no information ClientData blankClient;
Outline Create a blank object. Use write to output the raw data fig14_12.cpp to a file (passing a pointer to (2 of 2) the object and its size).
// output 100 blank records to file for ( int i = 0; i < 100; i++ ) outCredit.write( reinterpret_cast< const char * >( &blankClient ), sizeof( ClientData ) ); return 0; } // end main
© 2003 Prentice Hall, Inc. All rights reserved.
45
14.9 Writing Data Randomly to a RandomAccess File • Use seekp to write to exact location in file – Where does the first record begin? • Byte 0
– The second record? • Byte 0 + sizeof(object)
– Any record? • (Recordnum - 1) * sizeof(object)
© 2003 Prentice Hall, Inc. All rights reserved.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
// Fig. 14.13: fig14_13.cpp // Writing to a random access file. #include using using using using using
46
Outline fig14_13.cpp (1 of 4)
std::cerr; std::endl; std::cout; std::cin; std::ios;
#include using std::setw; #include using std::ofstream; #include #include "clientData.h"
// ClientData class definition
© 2003 Prentice Hall, Inc. All rights reserved.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
47
int main() { int accountNumber; char lastName[ 15 ]; char firstName[ 10 ]; double balance;
Outline fig14_13.cpp Open file for raw (binary) (2 of 4) writing.
ofstream outCredit( "credit.dat", ios::binary ); // exit program if ofstream cannot open file if ( !outCredit ) { cerr << "File could not be opened." << endl; exit( 1 ); } // end if cout << "Enter account number " << "(1 to 100, 0 to end input)\n? ";
Get account number, put into number object. It has not yet been written to file.
// require user to specify account ClientData client; cin >> accountNumber; client.setAccountNumber( accountNumber );
© 2003 Prentice Hall, Inc. All rights reserved.
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
// user enters information, which is copied into file while ( client.getAccountNumber() > 0 && client.getAccountNumber() <= 100 ) { // user enters last name, first name and balance cout << "Enter lastname, firstname, balance\n? "; cin >> setw( 15 ) >> lastName; cin >> setw( 10 ) >> firstName; cin >> balance;
48
Outline fig14_13.cpp (3 of 4)
// set record lastName, firstName and balance values Position outCredit to the client.setLastName( lastName ); proper location in the file client.setFirstName( firstName ); (based on the account client.setBalance( balance );
number). // seek position in file of user-specified record outCredit.seekp( ( client.getAccountNumber() - 1 ) * Write ClientData sizeof( ClientData ) );
object to file at specified position.
// write user-specified information in file outCredit.write( reinterpret_cast< const char * >( &client ), sizeof( ClientData ) );
© 2003 Prentice Hall, Inc. All rights reserved.
70 71 72 73 74 75 76 77 78 79
// enable user to specify another account number cout << "Enter account number\n? "; cin >> accountNumber; client.setAccountNumber( accountNumber ); } // end while
49
Outline fig14_13.cpp (4 of 4)
return 0; } // end main
© 2003 Prentice Hall, Inc. All rights reserved.
Enter account number (1 to ? 37 Enter lastname, firstname, ? Barker Doug 0.00 Enter account number ? 29 Enter lastname, firstname, ? Brown Nancy -24.54 Enter account number ? 96 Enter lastname, firstname, ? Stone Sam 34.98 Enter account number ? 88 Enter lastname, firstname, ? Smith Dave 258.34 Enter account number ? 33 Enter lastname, firstname, ? Dunn Stacey 314.33 Enter account number ? 0
100, 0 to end input)
50
Outline
balance
Notice that accounts can be created in any order.
fig14_13.cpp output (1 of 1)
balance
balance
balance
balance
© 2003 Prentice Hall, Inc. All rights reserved.
51
14.10 Reading Data Sequentially from a Random-Access File • read - similar to write – Reads raw bytes from file into memory – inFile.read( reinterpret_cast( &number ), sizeof( int ) );
• &number: location to store data • sizeof(int): how many bytes to read
– Do not use inFile >> number with raw bytes • >> expects char *
• Upcoming program – Output data from a random-access file – Go through each record sequentially • If no data (accountNumber == 0) then skip
© 2003 Prentice Hall, Inc. All rights reserved.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
// Fig. 14.14: fig14_14.cpp // Reading a random access file. #include using using using using using using using using
std::cout; std::endl; std::ios; std::cerr; std::left; std::right; std::fixed; std::showpoint;
52
Outline fig14_14.cpp (1 of 3)
#include using std::setprecision; using std::setw; #include using std::ifstream; using std::ostream; #include // exit protoyype #include "clientData.h" // ClientData class definition
© 2003 Prentice Hall, Inc. All rights reserved.
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
void outputLine( ostream&, const ClientData & ); int main() { ifstream inCredit( "credit.dat", ios::in );
53
Outline fig14_14.cpp (2 of 3)
// exit program if ifstream cannot open file if ( !inCredit ) { cerr << "File could not be opened." << endl; exit( 1 ); } // end if
Read sizeof(ClientData) bytes and put empty
cout << left << setw( 10 ) << "Account" << setw( 16 ) into object client. This may be an << "Last Name" << setw( 11 ) << "First Name" << left record. << setw( 10 ) << right << "Balance" << endl; ClientData client; // create record // read first record from file inCredit.read( reinterpret_cast< char * >( &client ), sizeof( ClientData ) );
© 2003 Prentice Hall, Inc. All rights reserved.
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
54
// read all records from file while ( inCredit && !inCredit.eof() ) {
Outline
// display record if ( client.getAccountNumber() != 0 ) outputLine( cout, client );
Loop exits if there is an error fig14_14.cpp reading (inCredit == 0) (3 of 3) or EOF is found (inCredit.eof() == 1)
// read next from file inCredit.read( reinterpret_cast< char * >( &client ), sizeof( ClientData ) ); } // end while return 0; } // end main
Output non-empty accounts. Note that outputLine takes an ostream argument. We could easily output to another file (opened with an ofstream object, which derives from ostream).
// display single record void outputLine( ostream &output, const ClientData &record ) { output << left << setw( 10 ) << record.getAccountNumber() << setw( 16 ) << record.getLastName().data() << setw( 11 ) << record.getFirstName().data() << setw( 10 ) << setprecision( 2 ) << right << fixed << showpoint << record.getBalance() << endl; } // end outputLine
© 2003 Prentice Hall, Inc. All rights reserved.
Account 29 33 37 88 96
Last Name Brown Dunn Barker Smith Stone
First Name Nancy Stacey Doug Dave Sam
Balance -24.54 314.33 0.00 258.34 34.98
55
Outline fig14_14.cpp output (1 of 1)
© 2003 Prentice Hall, Inc. All rights reserved.
56
14.11 Example: A Transaction-Processing Program • Instant access for bank accounts – Use random access file (data in client.dat)
• Give user menu – Option 1: store accounts to print.txt Account 29 33 37 88 96
Last Name Brown Dunn Barker Smith Stone
First Name Nancy Stacey Doug Dave Sam
Balance -24.54 314.33 0.00 258.34 34.98
– Option 2: update record Enter account to update (1 - 100): 37 37 Barker Doug Enter charge (+) or payment (-): +87.99 37 Barker Doug
© 2003 Prentice Hall, Inc. All rights reserved.
0.00
87.99
57
14.11 Example: A Transaction-Processing Program • Menu options (continued) – Option 3: add new record Enter new account number (1 - 100): 22 Enter lastname, firstname, balance ? Johnston Sarah 247.45
– Option 4: delete record Enter account to delete (1 - 100): 29 Account #29 deleted.
• To open file for reading and writing – Use fstream object – "Or" file-open modes together fstream inOutCredit( "credit.dat", ios::in | ios::out );
© 2003 Prentice Hall, Inc. All rights reserved.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
// Fig. 14.15: fig14_15.cpp // This program reads a random access file sequentially, updates // data previously written to the file, creates data to be placed // in the file, and deletes data previously in the file. #include using using using using using using using using using
58
Outline fig14_15.cpp (1 of 14)
std::cout; std::cerr; std::cin; std::endl; std::ios; std::left; std::right; std::fixed; std::showpoint;
#include using std::ofstream; using std::ostream; using std::fstream; #include using std::setw; using std::setprecision; #include #include "clientData.h"
// exit prototype // ClientData class definition
© 2003 Prentice Hall, Inc. All rights reserved.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
59 int enterChoice(); void printRecord( fstream& ); void updateRecord( fstream& ); void newRecord( fstream& ); void deleteRecord( fstream& ); void outputLine( ostream&, const ClientData & ); int getAccount( const char * const );
Outline fig14_15.cpp (2 of 14)
enum Choices { PRINT = 1, UPDATE, NEW, DELETE, END };
Open file for reading and
int main() writing (fstream object { // open file for reading and writing needed). fstream inOutCredit( "credit.dat", ios::in | ios::out ); // exit program if fstream cannot open file if ( !inOutCredit ) { cerr << "File could not be opened." << endl; exit ( 1 ); } // end if
© 2003 Prentice Hall, Inc. All rights reserved.
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
int choice; // enable user to specify action while ( ( choice = enterChoice() ) != END ) { switch ( choice ) {
60
Outline fig14_15.cpp (3 of 14)
// create text file from record file case PRINT: printRecord( inOutCredit ); break; // update record case UPDATE: updateRecord( inOutCredit ); break; // create record case NEW: newRecord( inOutCredit ); break; // delete existing record case DELETE: deleteRecord( inOutCredit ); break;
© 2003 Prentice Hall, Inc. All rights reserved.
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
61
int choice;
Outline
// enable user to specify action while ( ( choice = enterChoice() ) != END ) { switch ( choice ) {
Displays menu and returns user's choice.
fig14_15.cpp (4 of 14)
// create text file from record file case PRINT: printRecord( inOutCredit ); break; // update record case UPDATE: updateRecord( inOutCredit ); break; // create record case NEW: newRecord( inOutCredit ); break; // delete existing record case DELETE: deleteRecord( inOutCredit ); break;
© 2003 Prentice Hall, Inc. All rights reserved.
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
// display error if user does not select valid choice default: cerr << "Incorrect choice" << endl; break; } // end switch
62
Outline fig14_15.cpp (5 of 14)
inOutCredit.clear(); // reset end-of-file indicator } // end while return 0; } // end main // enable user to input menu choice int enterChoice() { // display available options cout << "\nEnter your choice" << endl << "1 - store a formatted text file of accounts" << endl << " called \"print.txt\" for printing" << endl << "2 - update an account" << endl << "3 - add a new account" << endl << "4 - delete an account" << endl << "5 - end program\n? ";
© 2003 Prentice Hall, Inc. All rights reserved.
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
63 int menuChoice; cin >> menuChoice; // receive choice from user return menuChoice;
Outline fig14_15.cpp (6 of 14)
} // end function enterChoice // create formatted text file for printing Output to print.txt. First, void printRecord( fstream &readFromFile ) print the header for the table. { // create text file ofstream outPrintFile( "print.txt", ios::out ); // exit program if ofstream cannot create file if ( !outPrintFile ) { cerr << "File could not be created." << endl; exit( 1 ); } // end if outPrintFile << left << setw( 10 ) << "Account" << setw( 16 ) << "Last Name" << setw( 11 ) << "First Name" << right << setw( 10 ) << "Balance" << endl;
© 2003 Prentice Hall, Inc. All rights reserved.
131 // set file-position pointer to beginning of record file 132 readFromFile.seekg( 0 ); 133 134 // read first record from record file Go to front of file, read fig14_15.cpp 135 ClientData client; account data,(7and print record of 14) 136 readFromFile.read( reinterpret_cast< char * >( &client ), if not empty. 137 sizeof( ClientData ) ); 138 Note that outputLine 139 // copy all records from record file into text file takes an ostream object 140 while ( !readFromFile.eof() ) { (base of ofstream). It can 141 easily print to a file (as in this 142 // write single record to text file 143 if ( client.getAccountNumber() != 0 ) case) or cout. 144 outputLine( outPrintFile, client ); 145 146 // read next record from record file 147 readFromFile.read( reinterpret_cast< char * >( &client ), 148 sizeof( ClientData ) ); 149 150 } // end while 151 152 } // end function printRecord 153
Outline
© 2003 Prentice Hall, Inc. All rights reserved.
64
154 // update balance in record 155 void updateRecord( fstream &updateFile ) 156 { 157 // obtain number of account to update 158 int accountNumber = getAccount( "Enter account to update" ); 159 160 // move file-position pointer to correct record in file This is fstream (I/O) 161 updateFile.seekg( 162 ( accountNumber - 1 ) * sizeof( ClientData ) ); because we must read the old 163 balance, update it, and write 164 // read first record from file the new balance. 165 ClientData client; 166 updateFile.read( reinterpret_cast< char * >( &client ), 167 sizeof( ClientData ) ); 168 169 // update record 170 if ( client.getAccountNumber() != 0 ) { 171 outputLine( cout, client ); 172 173 // request user to specify transaction 174 cout << "\nEnter charge (+) or payment (-): "; 175 double transaction; // charge or payment 176 cin >> transaction; 177 178 // update record balance 179 double oldBalance = client.getBalance(); 180 client.setBalance( oldBalance + transaction ); 181 outputLine( cout, client ); 182
65
Outline fig14_15.cpp (8 of 14)
© 2003 Prentice Hall, Inc. All rights reserved.
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
66
// move file-position pointer to correct record in file updateFile.seekp( ( accountNumber - 1 ) * sizeof( ClientData ) );
Outline fig14_15.cpp (9 of 14)
// write updated record over old record in file updateFile.write( reinterpret_cast< const char * >( &client ), sizeof( ClientData ) ); } // end if // display error if account does not exist else This is fstream because cerr << "Account #" << accountNumber read to see if a non-empty << " has no information." << endl; } // end function updateRecord
we
record already exists. If not, we write a new record.
// create and insert record void newRecord( fstream &insertInFile ) { // obtain number of account to create int accountNumber = getAccount( "Enter new account number" ); // move file-position pointer to correct record in file insertInFile.seekg( ( accountNumber - 1 ) * sizeof( ClientData ) );
© 2003 Prentice Hall, Inc. All rights reserved.
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
67 // read record from file ClientData client; insertInFile.read( reinterpret_cast< char * >( &client ), sizeof( ClientData ) );
Outline fig14_15.cpp (10 of 14)
// create record, if record does not previously exist if ( client.getAccountNumber() == 0 ) { char lastName[ 15 ]; char firstName[ 10 ]; double balance; // user enters last name, first name and balance cout << "Enter lastname, firstname, balance\n? "; cin >> setw( 15 ) >> lastName; cin >> setw( 10 ) >> firstName; cin >> balance; // use values to populate account values client.setLastName( lastName ); client.setFirstName( firstName ); client.setBalance( balance ); client.setAccountNumber( accountNumber );
© 2003 Prentice Hall, Inc. All rights reserved.
235 // move file-position pointer to correct record in file 236 insertInFile.seekp( ( accountNumber - 1 ) * 237 sizeof( ClientData ) ); 238 239 // insert record in file 240 insertInFile.write( 241 reinterpret_cast< const char * >( &client ), 242 sizeof( ClientData ) ); 243 244 } // end if 245 246 // display error if account previously exists 247 else 248 cerr << "Account #" << accountNumber 249 << " already contains information." << endl; 250 251 } // end function newRecord 252
68
Outline fig14_15.cpp (11 of 14)
© 2003 Prentice Hall, Inc. All rights reserved.
253 // delete an existing record 254 void deleteRecord( fstream &deleteFromFile ) 255 { 256 // obtain number of account to delete fig14_15.cpp 257 int accountNumber = getAccount( "Enter account to delete" ); (12 of 14) 258 259 // move file-position pointer to correct record in file 260 deleteFromFile.seekg( 261 ( accountNumber - 1 ) * sizeof( ClientData ) ); fstream because we read to 262 check if the account exits. If 263 // read record from file it does, we write blank data 264 ClientData client; (erase it). 265 deleteFromFile.read( reinterpret_cast< char * >( &client ), If it does not exist, there is no need to delete it. 266 sizeof( ClientData ) ); 267 268 // delete record, if record exists in file 269 if ( client.getAccountNumber() != 0 ) { 270 ClientData blankClient; 271 272 // move file-position pointer to correct record in file 273 deleteFromFile.seekp( ( accountNumber - 1 ) * 274 sizeof( ClientData ) ); 275
Outline
© 2003 Prentice Hall, Inc. All rights reserved.
69
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
// replace existing record with blank record deleteFromFile.write( reinterpret_cast< const char * >( &blankClient ), sizeof( ClientData ) ); cout << "Account #" << accountNumber << " deleted.\n";
70
Outline fig14_15.cpp (13 of 14)
} // end if // display error if record does not exist else is very cerr << "Account #" << accountNumber outputLine << " is empty.\n"; } // end deleteRecord
flexible, and can output to any ostream object (such as a file or cout).
// display single record void outputLine( ostream &output, const ClientData &record ) { output << left << setw( 10 ) << record.getAccountNumber() << setw( 16 ) << record.getLastName().data() << setw( 11 ) << record.getFirstName().data() << setw( 10 ) << setprecision( 2 ) << right << fixed << showpoint << record.getBalance() << endl; } // end function outputLine
© 2003 Prentice Hall, Inc. All rights reserved.
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
// obtain account-number value from user int getAccount( const char * const prompt ) { int accountNumber; // obtain account-number value do { cout << prompt << " (1 - 100): "; cin >> accountNumber;
71
Outline fig14_15.cpp (14 of 14)
} while ( accountNumber < 1 || accountNumber > 100 ); return accountNumber; } // end function getAccount
© 2003 Prentice Hall, Inc. All rights reserved.
72
14.12 Input/Output of Objects • I/O of objects – Chapter 8 (overloaded >>) – Only object's data transmitted • Member functions available internally
– When objects stored in file, lose type info (class, etc.) • Program must know type of object when reading
– One solution • When writing, output object type code before real object • When reading, read type code – Call proper overloaded function (switch)
© 2003 Prentice Hall, Inc. All rights reserved.