14.4 Reading Data from a Sequential File

Files store data so it may be retrieved for processing when needed. The previous section demonstrated how to create a file for sequential access. We now discuss how to read data sequentially from a file. Figure 14.5 reads and displays the records from the clients.txt file that we created using the program of Fig. 14.2. Creating an ifstream object opens a file for input. The ifstream constructor can receive the filename and the file-open mode as arguments. Line 14 creates an ifstream object called inClientFile and associates it with the clients.txt file. The arguments in parentheses are passed to the ifstream constructor, which opens the file and establishes a “line of communication” with the file.

Good Programming Practice 14.1

If a file’s contents should not be modified, use ios::in to open it only for input. This prevents unintentional modification of the file’s contents and is another example of the principle of least privilege.

Fig. 14.5 Reading and printing a sequential file.

Alternate View

 1   // Fig. 14.5: Fig14_05.cpp
 2   // Reading and printing a sequential file.
 3   #include <iostream>
 4   #include <fstream> // file stream        
 5   #include <iomanip>
 6   #include <string>
 7   #include <cstdlib>
 8   using namespace std;
 9
10   void outputLine(int, const string&, double); // prototype
11
12   int main() {
13      // ifstream constructor opens the file          
14      ifstream inClientFile("clients.txt", ios::in);  
15
16      // exit program if ifstream could not open file
17      if (!inClientFile) {
18         cerr << "File could not be opened" << endl;
19         exit(EXIT_FAILURE);
20      }
21
22      cout << left << setw(10) << "Account" << setw(13)
23         << "Name" << "Balance
" << fixed << showpoint;
24
25      int account; // the account number
26      string name; // the account owner's name
27      double balance; // the account balance
28
29      // display each record in file
30      while (inClientFile >> account >> name >> balance) {
31         outputLine(account, name, balance);
32      }
33   }
34
35   // display single record from file
36   void outputLine(int account, const string& name, double balance) {
37      cout << left << setw(10) << account << setw(13) << name
38         << setw(7) << setprecision(2) << right << balance << endl;
39   }

Account    Name            Balance
100        Jones             24.98
200        Doe              345.67
300        White              0.00
400        Stone            -42.16
500        Rich             224.62

14.4.1 Opening a File for Input

Objects of class ifstream are opened for input by default, so the statement


ifstream inClientFile("clients.txt");

opens clients.txt for input. Just as with an ofstream object, an ifstream object can be created without opening a specific file, because a file can be attached to it later. Before attempting to retrieve data from the file, line 17 uses the condition !inClientFile to determine whether the file was opened successfully.

14.4.2 Reading from the File

Line 30 reads a set of data (i.e., a record) from the file. After line 30 executes the first time, account has the value 100, name has the value "Jones" and balance has the value 24.98. Each time line 30 executes, it reads another record into the variables account, name and balance. Line 31 displays the records, using function outputLine (lines 36–39), which uses parameterized stream manipulators to format the data for display. When the end of file is reached, the implicit call to operator bool in the while condition returns false, the ifstream destructor closes the file and the program terminates.

14.4.3 File-Position Pointers

Programs normally read sequentially from the beginning of a file and read all the data consecutively until the desired data is found. It might be necessary to process the file sequentially several times (from the beginning) during the execution of a program. istream and ostream provide member functions—seekg (“seek get”) and seekp (“seek put”), respectively—to reposition the file-position pointer (the byte number of the next byte in the file to be read or written). Each istream object has a get pointer, which indicates the byte number in the file from which the next input is to occur, and each ostream object has a put pointer, which indicates the byte number in the file at which the next output should be placed. The statement


inClientFile.seekg(0);

repositions the file-position pointer to the beginning of the file (location 0) attached to inClientFile. The argument to seekg is an integer. A second argument can be specified to indicate the seek direction, which can be ios::beg (the default) for positioning relative to the beginning of a stream, ios::cur for positioning relative to the current position in a stream or ios::end for positioning backward relative to the end of a stream. The file-position pointer is an integer value that specifies the location in the file as a number of bytes from the file’s starting location (this is also referred to as the offset from the beginning of the file). Some examples of positioning the get file-position pointer are


// position to the nth byte of fileObject (assumes ios::beg)
fileObject.seekg(n);
// position n bytes in fileObject
fileObject.seekg(n, ios::cur);
// position n bytes back from end of fileObject
fileObject.seekg(n, ios::end);
// position at end of fileObject
fileObject.seekg(0, ios::end);

The same operations can be performed using ostream member function seekp. Member functions tellg and tellp are provided to return the current locations of the get and put pointers, respectively. The following statement assigns the get file-position pointer value to variable location of type long:


location = fileObject.tellg();

14.4.4 Case Study: Credit Inquiry Program

Figure 14.6 enables a credit manager to display the account information for those customers with zero balances (i.e., customers who do not owe the company any money), credit (negative) balances (i.e., customers to whom the company owes money), and debit (positive) balances (i.e., customers who owe the company money for goods and services received in the past). The program displays a menu and allows the credit manager to enter one of three options to obtain credit information. Option 1 produces a list of accounts with zero balances. Option 2 produces a list of accounts with credit balances. Option 3 produces a list of accounts with debit balances. Option 4 terminates program execution. Entering an invalid option displays the prompt to enter another choice. Lines 61–62 enable the program to read from the beginning of the file after end-of-file has been read.





Fig. 14.6 Credit inquiry program.

Alternate View

  1   // Fig. 14.6: Fig14_06.cpp
  2   // Credit inquiry program.
  3   #include <iostream>
  4   #include <fstream>
  5   #include <iomanip>
  6   #include <string>
  7   #include <cstdlib>
  8   using namespace std;
  9
 10   enum class RequestType {
 11      ZERO_BALANCE = 1, CREDIT_BALANCE, DEBIT_BALANCE, END};
 12   RequestType getRequest();
 13   bool shouldDisplay(RequestType, double);
 14   void outputLine(int, const string&, double);
 15
 16   int main() {
 17      // ifstream constructor opens the file
 18      ifstream inClientFile{"clients.txt", ios::in};
 19
 20      // exit program if ifstream could not open file
 21      if (!inClientFile) {
 22         cerr << "File could not be opened" << endl;
 23         exit(EXIT_FAILURE);
 24      }
 25
 26      // get user's request (e.g., zero, credit or debit balance)
 27      RequestType request{getRequest()};
 28
 29      // process user's request
 30      while (request != RequestType::END) {
 31         switch (request) {
 32            case RequestType::ZERO_BALANCE:
 33               cout << "
Accounts with zero balances:
";
 34               break;
 35            case RequestType::CREDIT_BALANCE:
 36               cout << "
Accounts with credit balances:
";
 37               break;
 38            case RequestType::DEBIT_BALANCE:
 39               cout << "
Accounts with debit balances:
";
 40               break;
 41         }
 42
 43         int account; // the account number
 44         string name; // the account owner's name
 45         double balance; // the account balance
 46
 47         // read account, name and balance from file
 48         inClientFile >> account >> name >> balance;
 49
 50         // display file contents (until eof)
 51         while (!inClientFile.eof()) {
 52            // display record
 53            if (shouldDisplay(request, balance)) {
 54               outputLine(account, name, balance);
 55            }
 56
 57            // read account, name and balance from file
 58            inClientFile >> account >> name >> balance;
 59         }
 60
 61         inClientFile.clear(); // reset eof for next input          
 62         inClientFile.seekg(0); // reposition to beginning of file  
 63         request = getRequest(); // get additional request from user
 64      }
 65
 66      cout << "End of run." << endl;
 67   }
 68
 69   // obtain request from user
 70   RequestType getRequest() {
 71      // display request options
 72      cout << "
Enter request
"
 73         << " 1 - List accounts with zero balances
"
 74         << " 2 - List accounts with credit balances
"
 75         << " 3 - List accounts with debit balances
"
 76         << " 4 - End of run" << fixed << showpoint;
 77      int type; // request from user
 78
 79      do { // input user request
 80         cout << "
? ";
 81         cin >> type;
 82      } while (type < static_cast<int>(RequestType::ZERO_BALANCE) ||
 83           type > static_cast<int>(RequestType::END));
 84
 85      return static_cast<RequestType>(type);
 86   }
 87
 88   // determine whether to display given record
 89   bool shouldDisplay(RequestType type, double balance) {
 90      // determine whether to display zero balances
 91      if (type == RequestType::ZERO_BALANCE && balance == 0) {
 92         return true;
 93      }
 94
 95      // determine whether to display credit balances
 96      if (type == RequestType::CREDIT_BALANCE && balance < 0) {
 97         return true;
 98      }
 99
100      // determine whether to display debit balances
101      if (type == RequestType::DEBIT_BALANCE && balance > 0) {
102         return true;
103      }
104
105         return false;
106   }
107
108   // display single record from file
109   void outputLine(int account, const string& name, double balance) {
110      cout << left << setw(10) << account << setw(13) << name
111         << setw(7) << setprecision(2) << right << balance << endl;
112   }

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

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

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

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.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset