MFC Programmer's SourceBook : Thinking in C++
Bruce Eckel's Thinking in C++, 2nd Ed Contents | Prev | Next

Reading and writing files

We could use IO redirection in order to read files and write files, as shown previously. In C, the process of opening and manipulating files requires a lot of language background to prepare you for the complexity of the operations. However, the C++ iostream library provides a very simple way to manipulate files, and so this functionality can be introduced much earlier than it would be in C.

To open files for reading and writing, you must include <fstream>. Although this will automatically include <iostream>, it’s generally prudent to explicitly include <iostream> if you’re planning to use cin, cout, etc.

To open a file for reading, you create an ifstream object, which then behaves like cin. To open a file for writing, you create an ofstream object, which then behaves like cout. Once you’ve opened the file, you can read from it or write to it just as you would with any other iostream object. It’s that simple (which is, of course, the whole point).

One of the most useful functions in the iostream library is getline( ), which allows you to read one line (terminated by a newline) into a string object [18]. The first argument is the ifstream object you’re reading from, and the second argument is the string object. When the function call is finished, the string object will contain the line.

Here’s a simple example, which copies the contents of one file into another:

//: C02:Scopy.cpp
// Copy one file to another, a line at a time
#include <string>
#include <fstream>
using namespace std;

int main() {
  ifstream in("Scopy.cpp"); // Open for reading
  ofstream out("Scopy2.cpp"); // Open for writing
  string s;
  while(getline(in, s)) // Discards newline char
    out << s << "\n"; // ... must add it back
} ///:~ 

To open the files, you just hand the ifstream and ofstream objects the file names you want to create, as seen above.

There is a new concept introduced here, which is the while loop. Although this will be explained in detail in the next chapter, the basic idea is that the expression in parentheses following the while controls the execution of the subsequent statement (which can also be multiple statements, wrapped inside curly braces). As long as the expression in parentheses (in this case, getline(in, s) ) produces a “true” result, then the statement controlled by the while will continue to execute. It turns out that getline( ) will return a value that can be interpreted as “true” if another line has been successfully read, and “false” upon reaching the end of the input. Thus, the above while loop reads every line in the input file and sends each line to the output file.

getline( ) reads each line until it discovers a newline (the termination character can be changed, but that won’t be an issue until Chapter XX). However, it discards the newline and doesn’t store it in the resulting string object. Thus, if we want the copied file to look just like the source file, we must add the newline back in, as shown.

Another interesting example is to copy the entire file into a single string object:

//: C02:FillString.cpp
// Read an entire file into a single string
#include <string>
#include <fstream>
using namespace std;

int main() {
  ifstream in("FillString.cpp");
  string s, line;
  while(getline(in, line))
    s += line + "\n";
  cout << s;
} ///:~ 

Because of the dynamic nature of strings, you don’t have to worry about how much storage to allocate for a string – you can just keep adding things and the string will keep expanding to hold whatever you put into it.

One of the nice things about putting an entire file into a string is that the string class has many functions for searching and manipulation which would then allow you to modify the file as a single string. However, this has its limitations. For one thing, it is often convenient to treat a file as a collection of lines instead of just a big blob of text. For example, if you want to add line numbering it’s much easier if you have each line as a separate string object. To accomplish this, we’ll need another approach.


[18] There are actually a number of variants of getline( ), which will be discussed thoroughly in the iostreams chapter, Chapter XX.

Contents | Prev | Next


Go to CodeGuru.com
Contact: webmaster@codeguru.com
© Copyright 1997-1999 CodeGuru