8.2.1. Using File Stream Objects

Image

When we want to read or write a file, we define a file stream object and associate that object with the file. Each file stream class defines a member function named open that does whatever system-specific operations are required to locate the given file and open it for reading or writing as appropriate.

When we create a file stream, we can (optionally) provide a file name. When we supply a file name, open is called automatically:

ifstream in(ifile); // construct an ifstream and open the given file
ofstream out;       // output file stream that is not associated with any file

This code defines in as an input stream that is initialized to read from the file named by the string argument ifile. It defines out as an output stream that is not yet associated with a file. With the new standard, file names can be either library strings or C-style character arrays (§ 3.5.4, p. 122). Previous versions of the library allowed only C-style character arrays.

Image
Using an fstream in Place of an iostream&

As we noted in § 8.1 (p. 311), we can use an object of an inherited type in places where an object of the original type is expected. This fact means that functions that are written to take a reference (or pointer) to one of the iostream types can be called on behalf of the corresponding fstream (or sstream) type. That is, if we have a function that takes an ostream&, we can call that function passing it an ofstream object, and similarly for istream& and ifstream.

For example, we can use the read and print functions from § 7.1.3 (p. 261) to read from and write to named files. In this example, we’ll assume that the names of the input and output files are passed as arguments to main6.2.5, p. 218):

ifstream input(argv[1]);   // open the file of sales transactions
ofstream output(argv[2]);  // open the output file
Sales_data total;          // variable to hold the running sum
if (read(input, total)) {  // read the first transaction
    Sales_data trans;      // variable to hold data for the next transaction
    while(read(input, trans)) {    // read the remaining transactions
        if (total.isbn() == trans.isbn()) //  check isbns
            total.combine(trans);  // update the running total
        else {
            print(output, total) << endl; //  print the results
            total = trans;         // process the next book
        }
    }
    print(output, total) << endl;  // print the last transaction
} else                             // there was no input
    cerr << "No data?!" << endl;

Aside from using named files, this code is nearly identical to the version of the addition program on page 255. The important part is the calls to read and to print. We can pass our fstream objects to these functions even though the parameters to those functions are defined as istream& and ostream&, respectively.

The open and close Members

When we define an empty file stream object, we can subsequently associate that object with a file by calling open:

ifstream in(ifile); // construct an ifstreamand open the given file
ofstream out;       // output file stream that is not associated with any file
out.open(ifile + ".copy");  // open the specified file

If a call to open fails, failbit is set (§ 8.1.2, p. 312). Because a call to open might fail, it is usually a good idea to verify that the open succeeded:

if (out)     // check that the open succeeded
    // the open succeeded, so we can use the file

This condition is similar to those we’ve used on cin. If the open fails, this condition will fail and we will not attempt to use out.

Once a file stream has been opened, it remains associated with the specified file. Indeed, calling open on a file stream that is already open will fail and set failbit. Subsequent attempts to use that file stream will fail. To associate a file stream with a different file, we must first close the existing file. Once the file is closed, we can open a new one:

in.close();               // close the file
in.open(ifile + "2");     // open another file

If the open succeeds, then open sets the stream’s state so that good() is true.

Automatic Construction and Destruction

Consider a program whose main function takes a list of files it should process (§ 6.2.5, p. 218). Such a program might have a loop like the following:

// for each file passed to the program
for (auto p = argv + 1; p != argv + argc; ++p) {
    ifstream input(*p);   // create input and open the file
    if (input) {          // if the file is ok, ''process'' this file
        process(input);
    } else
        cerr << "couldn't open: " + string(*p);
} // input goes out of scope and is destroyed on each iteration

Each iteration constructs a new ifstream object named input and opens it to read the given file. As usual, we check that the open succeeded. If so, we pass that file to a function that will read and process the input. If not, we print an error message and continue.

Because input is defined inside the block that forms the for body, it is created and destroyed on each iteration (§ 6.1.1, p. 205). When an fstream object goes out of scope, the file it is bound to is automatically closed. On the next iteration, input is created anew.


Image Note

When an fstream object is destroyed, close is called automatically.



Exercises Section 8.2.1

Exercise 8.4: Write a function to open a file for input and read its contents into a vector of strings, storing each line as a separate element in the vector.

Exercise 8.5: Rewrite the previous program to store each word in a separate element.

Exercise 8.6: Rewrite the bookstore program from § 7.1.1 (p. 256) to read its transactions from a file. Pass the name of the file as an argument to main6.2.5, p. 218).


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

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