// 21. Потоци и работа с файлове: йерархия на данни; последователни файлове; // файлове с пряк достъп; работа с низови потоци. // // Fig. 14.4: fig14_04.cpp // Create a sequential file. #include using std::cout; using std::cin; using std::ios; using std::cerr; using std::endl; #include using std::ofstream; #include // 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 ); } // end if cout << "Enter the account, name, and balance." << endl << "Enter end-of-file to end input.\n? "; int account; char name[ 30 ]; double balance; // 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; // ofstream destructor closes file } // end main /***********************************************/ // 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 { 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; // accessor functions for firstName void setFirstName( string ); string getFirstName() const; // accessor functions for balance void setBalance( double ); double getBalance() const; private: int accountNumber; char lastName[ 15 ]; char firstName[ 10 ]; double balance; }; // end class ClientData #endif /****/ // Fig. 14.11: ClientData.cpp // Class ClientData stores customer's credit information. #include using std::string; #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 // set account-number value void ClientData::setAccountNumber( int accountNumberValue ) { accountNumber = accountNumberValue; } // 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'; } // end function setLastName // get first-name value string ClientData::getFirstName() const { return firstName; } // 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 // get balance value double ClientData::getBalance() const { return balance; } // end function getBalance // set balance value void ClientData::setBalance( double balanceValue ) { balance = balanceValue; } // end function setBalance /***************************/ // Fig. 14.12: fig14_12.cpp // Creating a randomly accessed file. #include 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 ); // exit program if ofstream could not open file if ( !outCredit ) { cerr << "File could not be opened." << endl; exit( 1 ); } // end if // create ClientData with no information ClientData blankClient; // 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 /***********/ // Fig. 14.13: fig14_13.cpp // Writing to a random access file. #include using std::cerr; using std::endl; using std::cout; using std::cin; using std::ios; #include using std::setw; #include using std::ofstream; #include #include "clientData.h" // ClientData class definition int main() { int accountNumber; char lastName[ 15 ]; char firstName[ 10 ]; double balance; 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? "; // require user to specify account number ClientData client; cin >> accountNumber; client.setAccountNumber( accountNumber ); // 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; // set record lastName, firstName and balance values client.setLastName( lastName ); client.setFirstName( firstName ); client.setBalance( balance ); // seek position in file of user-specified record outCredit.seekp( ( client.getAccountNumber() - 1 ) * sizeof( ClientData ) ); // write user-specified information in file outCredit.write( reinterpret_cast< const char * >( &client ), sizeof( ClientData ) ); // enable user to specify another account number cout << "Enter account number\n? "; cin >> accountNumber; client.setAccountNumber( accountNumber ); } // end while return 0; } // end main // Fig. 14.14: fig14_14.cpp // Reading a random access file. #include using std::cout; using std::endl; using std::ios; using std::cerr; using std::left; using std::right; using std::fixed; using std::showpoint; #include using std::setprecision; using std::setw; #include using std::ifstream; using std::ostream; #include #include "clientData.h" // ClientData class definition void outputLine( ostream&, const ClientData & ); int main() { ifstream inCredit( "credit.dat", ios::in ); // exit program if ifstream cannot open file if ( !inCredit ) { cerr << "File could not be opened." << endl; exit( 1 ); } // end if cout << left << setw( 10 ) << "Account" << setw( 16 ) << "Last Name" << setw( 11 ) << "First Name" << left << setw( 10 ) << right << "Balance" << endl; ClientData client; // create record // read first record from file inCredit.read( reinterpret_cast< char * >( &client ), sizeof( ClientData ) ); // read all records from file while ( inCredit && !inCredit.eof() ) { // display record if ( client.getAccountNumber() != 0 ) outputLine( cout, client ); // read next from file inCredit.read( reinterpret_cast< char * >( &client ), sizeof( ClientData ) ); } // end while return 0; } // end main // 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 /******************************************************/ // 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 std::cout; using std::cerr; using std::cin; using std::endl; using std::ios; using std::left; using std::right; using std::fixed; using std::showpoint; #include using std::ofstream; using std::ostream; using std::fstream; #include using std::setw; using std::setprecision; #include #include "clientData.h" // ClientData class definition int enterChoice(); void printRecord( fstream& ); void updateRecord( fstream& ); void newRecord( fstream& ); void deleteRecord( fstream& ); void outputLine( ostream&, const ClientData & ); int getAccount( const char * const ); enum Choices { PRINT = 1, UPDATE, NEW, DELETE, END }; int main() { // open file for reading and writing 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 int choice; // enable user to specify action while ( ( choice = enterChoice() ) != END ) { switch ( choice ) { // 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; // display error if user does not select valid choice default: cerr << "Incorrect choice" << endl; break; } // end switch 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? "; int menuChoice; cin >> menuChoice; // receive choice from user return menuChoice; } // end function enterChoice // create formatted text file for printing void printRecord( fstream &readFromFile ) { // 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; // set file-position pointer to beginning of record file readFromFile.seekg( 0 ); // read first record from record file ClientData client; readFromFile.read( reinterpret_cast< char * >( &client ), sizeof( ClientData ) ); // copy all records from record file into text file while ( !readFromFile.eof() ) { // write single record to text file if ( client.getAccountNumber() != 0 ) outputLine( outPrintFile, client ); // read next record from record file readFromFile.read( reinterpret_cast< char * >( &client ), sizeof( ClientData ) ); } // end while } // end function printRecord // update balance in record void updateRecord( fstream &updateFile ) { // obtain number of account to update int accountNumber = getAccount( "Enter account to update" ); // move file-position pointer to correct record in file updateFile.seekg( ( accountNumber - 1 ) * sizeof( ClientData ) ); // read first record from file ClientData client; updateFile.read( reinterpret_cast< char * >( &client ), sizeof( ClientData ) ); // update record if ( client.getAccountNumber() != 0 ) { outputLine( cout, client ); // request user to specify transaction cout << "\nEnter charge (+) or payment (-): "; double transaction; // charge or payment cin >> transaction; // update record balance double oldBalance = client.getBalance(); client.setBalance( oldBalance + transaction ); outputLine( cout, client ); // move file-position pointer to correct record in file updateFile.seekp( ( accountNumber - 1 ) * sizeof( ClientData ) ); // 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 cerr << "Account #" << accountNumber << " has no information." << endl; } // end function updateRecord // 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 ) ); // read record from file ClientData client; insertInFile.read( reinterpret_cast< char * >( &client ), sizeof( ClientData ) ); // 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 ); // move file-position pointer to correct record in file insertInFile.seekp( ( accountNumber - 1 ) * sizeof( ClientData ) ); // insert record in file insertInFile.write( reinterpret_cast< const char * >( &client ), sizeof( ClientData ) ); } // end if // display error if account previously exists else cerr << "Account #" << accountNumber << " already contains information." << endl; } // end function newRecord // delete an existing record void deleteRecord( fstream &deleteFromFile ) { // obtain number of account to delete int accountNumber = getAccount( "Enter account to delete" ); // move file-position pointer to correct record in file deleteFromFile.seekg( ( accountNumber - 1 ) * sizeof( ClientData ) ); // read record from file ClientData client; deleteFromFile.read( reinterpret_cast< char * >( &client ), sizeof( ClientData ) ); // delete record, if record exists in file if ( client.getAccountNumber() != 0 ) { ClientData blankClient; // move file-position pointer to correct record in file deleteFromFile.seekp( ( accountNumber - 1 ) * sizeof( ClientData ) ); // replace existing record with blank record deleteFromFile.write( reinterpret_cast< const char * >( &blankClient ), sizeof( ClientData ) ); cout << "Account #" << accountNumber << " deleted.\n"; } // end if // display error if record does not exist else cerr << "Account #" << accountNumber << " is empty.\n"; } // end deleteRecord // 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 // 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; } while ( accountNumber < 1 || accountNumber > 100 ); return accountNumber; } // end function getAccount