14.10 Reading from a Random-Access File Sequentially

In the previous sections, we created a random-access file and wrote data to that file. In this section, we develop a program that reads the file sequentially and prints only those records that contain data. These programs produce an additional benefit. See if you can determine what it is; we’ll reveal it at the end of this section.

The istream function read inputs a specified number of bytes from the current position in the stream into an object. For example, line 28 (Fig. 14.12) reads the number of sizeof(ClientData) bytes from the file associated with inCredit and stores the data in client. Function read requires a first argument of type char*. Since &client is of type ClientData*, &client must be cast to char* using the cast operator reinterpret_cast.


Fig. 14.12 Reading a random-access file sequentially.

Alternate View

 1   // Fig. 14.12: Fig14_12.cpp
 2   // Reading a random-access file sequentially.
 3   #include <iostream>
 4   #include <iomanip>
 5   #include <fstream>
 6   #include <cstdlib>
 7   #include "ClientData.h" // ClientData class definition
 8   using namespace std;
 9
10   void outputLine(ostream&, const ClientData&); // prototype
11
12   int main() {
13      ifstream inCredit{"credit.dat", ios::in | ios::binary};
14
15      // exit program if ifstream cannot open file
16      if (!inCredit) {
17         cerr << "File could not be opened." << endl;
18         exit(EXIT_FAILURE);
19      }
20
21      // output column heads
22      cout << left << setw(10) << "Account" << setw(16) << "Last Name"
23         << setw(11) << "First Name" << setw(10) << right << "Balance
";
24
25      ClientData client; // create record
26
27      // read first record from file
28      inCredit.read(reinterpret_cast<char*>(&client), sizeof(ClientData));
29
30      // read all records from file
31      while (inCredit) {
32         // display record
33         if (client.getAccountNumber() != 0) {
34            outputLine(cout, client);
35         }
36
37         // read next from file
38         inCredit.read(reinterpret_cast<char*>(&client), sizeof(ClientData));
39      }
40   }
41
42   // display single record
43   void outputLine(ostream& output, const ClientData& record) {
44      output << left << setw(10) << record.getAccountNumber()
45         << setw(16) << record.getLastName()
46         << setw(11) << record.getFirstName()
47         << setw(10) << setprecision(2) << right << fixed
48         << showpoint << record.getBalance() << endl;
49   }

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

Figure 14.12 reads every record in the credit.dat file sequentially, checks each record to determine whether it contains data, and displays formatted outputs for records containing data. The condition in line 31 implicitly uses the stream’s operator bool to determine whether the end of file was reached or whether an error occurred when reading from the file—in both cases the while statement terminates. The data input from the file is output by function outputLine (lines 43–49), which takes two arguments—a reference to an ostream object and a clientData structure to be output. The ostream parameter type is interesting, because any ostream object (such as cout) or any object of a derived class of ostream (such as an object of type ofstream) can be supplied as the argument. This means that the same function can be used, for example, to perform output to the standard-output stream and to a file stream without writing separate functions.

What about that additional benefit we promised at the beginning of this section? If you examine the output window, you’ll notice that the records are listed in sorted order (by account number). This is a consequence of how we stored these records in the file, using direct-access techniques. Sorting using direct-access techniques is relatively fast. The speed is achieved by making the file large enough to hold every possible record that might be created. This, of course, means that the file could be occupied sparsely most of the time, resulting in a waste of storage. This is an example of the space-time trade-off: By using large amounts of space, we can develop a much faster sorting algorithm. Fortunately, the continuous reduction in price of storage units has made this less of an issue.

..................Content has been hidden....................

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