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, useios::into open it only for input. This prevents unintentional modification of the file’s contents and is another example of the principle of least privilege.
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 thefile-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.