Opening a File


A file must be opened before you can read from it or write to it. As discussed in the introduction to this section, opening a file establishes a path of communication between the file and a stream object in your program. Opening a file for writing is first discussed.

Opening a File for Writing

Either the ofstream or fstream object may be used to open a file for writing. However, the ifstream object cannot be used for this purpose because it only may be used to read from a file.

Both the ofstream and fstream objects may open a file one of two ways. The first way is using a member function named, as you might expect, open. The second alternative is using a constructor, which is explained in the The fstream or ofstream Constructor section later in this chapter.

The Open Member Function

Both the ofstream and fstream objects use an open member function, whose first argument is the name and location of the file to be opened. However, whether you include a second argument may depend on whether the ofstream or fstream object is calling the open member function, or whether you want to access the file in a different mode than the default.

First Argument ”Specifying the File to Be Opened

The file to be opened for writing need not already exist. If it does not, attempting to open it for writing to it automatically will create it with the specified name at the specified location. However, whether or not the file yet exists, you need to specify a file name and location.

Accordingly, whether the ofstream or fstream object is calling the function, the first argument specifies the name and location of the file to be opened. This information may be provided by using either the relative path or absolute path of the file. The terms relative path and absolute path are new, so let s discuss them now.

The relative path is the path relative to the location of your program. For example, the following statements open for writing a file, students.dat, that is in the same directory as the program:

 ofstream outfile;  outfile.open("students.dat"); 

By contrast, the absolute path is the path starting with the drive letter, and including each directory and subdirectory until the file is reached. For example, if the students.dat file is in the Classes subdirectory of the College directory of my C drive, it would be opened for writing, using the absolute path, as follows :

 ofstream outfile;   outfile.open("c:\college\classes\students.dat"); 
Note  

Two backslashes are necessary because one backslash is used to note an escape sequence. Two backslashes is the escape sequence for one backslash.

Whether you use a relative or absolute path, the argument for the open function need not be a string literal. It also may be a string variable, as in the following code fragment:

 ofstream outfile;  char filename[80];  cout << "Enter name of file: ";  cin >> filename;  outfile.open(filename); 
Note  

As a general rule, using a relative path is preferable, particularly if the program will be used on different machines. While the location of the data file relative to the program directory may remain the same, there is no guarantee that the particular placement of the program on one computer s directory structure will be the same as another s.

Second Argument ”File Mode

The second argument of the open member function defines the mode in which the file should be opened. One choice is whether the file should be opened for writing, reading, or both. However, there are other choices, each called a file mode flag . Table 13-1 lists the file mode flags:

Table 13-1: File Mode Flags

File Mode Flag

Description

ios::app

Append mode. The file's existing contents are preserved and all output is written to the end of the file.

ios::ate

If the file already exists, the program goes directly to the end of it. Output may be written anywhere in the file. This flag usually is used with binary mode.

ios::binary

Binary mode. Information is written to the file in binary format, rather than in the default text format.

ios::in

Input mode. Information will be read from the file. The file will not be created if it does not exist.

ios::out

Output mode. Information will be written to the file. By default, the existing file contents will be overwritten.

ios::trunc

If the file already exists, its contents will be truncated, another word for deleted or overwritten. This is the default mode of ios::out.

If you use the ofstream object to open a file, you do not need any file mode flags. Indeed, the examples in the previous section did not use any file mode flags. An ofstream object may only be used to open a file for writing, and cannot be used to open a file for reading. Therefore, there is no need to specify the ios::out flag; use of that flag is implied by use of the ofstream object to open the file.

However, you may want to use one or more file mode flags with the open member function of the ofstream object if you do not want the default, which is to open the file in text rather than binary mode and overwrite rather than append to the existing file contents. One example of when you might want to append is an error log file, which keeps track of errors that may occur in a program. When a new error occurs, you don t want to erase the history of prior errors, but rather you want to add to that history.

You can combine two or more flags when opening a file. For example, the following statements open a file in binary mode and to append rather than to overwrite. The two file mode flags are combined using the bitwise or operator ():

 ofstream outfile;  outfile.open("students.dat", ios::binary  ios::app); 
Note  

The bitwise or operator is not the same as the logical or operator even though they share the name or and the keystroke .

While you don t need to specify any file mode flags if you use the ofstream object to open a file, you should specify file mode flags if you use the fstream object to open a file. Whereas an ofstream object may only be used to open a file for writing and not reading, an fstream object may be used for both purposes. Therefore, you should specify whether you are using the open member function of the fstream object to open the file for writing, reading, or both.

The following code fragment uses the open member function of the fstream object to open the file for writing only:

 fstream afile;  afile.open("students.dat", ios::out); 

The fstream or ofstream Constructor

You also may use the fstream or ofstream constructor to open a file for writing. A constructor is a function that is automatically called when you attempt to create an instance of an object.

An object instance is akin to a variable of a primitive data type, such as an int. For example, the following statement could be characterized as creating an instance, named age, of an integer:

 int age; 

Similarly, the following statement creates an fstream instance named afile:

 fstream afile; 

Object constructors may be overloaded, such that for the same object there may be a constructor with no arguments, a constructor with one argument, a constructor with two arguments, and so forth. For example, the previous statement, fstream afile, is called the no-argument constructor of the fstream object.

The following statement calls the one-argument constructor of the ofstream object, both creating an ofstream instance and opening the file students.dat for output:

 ofstream outFile(students.dat", ios:out); 

The following statement calls the two-argument constructor of the fstream object, both creating an fstream instance and opening the file students.dat for output:

 fstream aFile(students.dat", ios:out); 

In essence, declaring an ofstream (or fstream ) variable in one statement and then calling the open member function in a second statement is analogous to declaring a primitive variable in one statement and then assigning it a value in a second statement, such as:

 int age;  age = 39; 

By contrast, using the one or two argument ofstream (or fstream ) constructor is analogous to initializing a primitive variable, such as:

 int age = 39; 

One alternative is not inherently better than the other. Usually, the specific needs of a particular program will dictate which alternative better fits your needs.

Opening a File for Reading

The discussion in the previous section concerning opening a file for writing also applies to opening a file for reading. The primary difference is that the object that calls the open member function, or whose constructor you may use, may be, in addition to an fstream object, an ifstream object instead of an ofstream object. Additionally, the file to be opened for reading must already exist. Unlike opening a file for writing, attempting to open a file for reading will not automatically create it if it does not yet exist. This issue is discussed further in the next section.

The following statements use the open member function of the ifstream object to open a file for reading:

 ifstream infile;  infile.open("students.dat"); 

You could accomplish the same purpose using the fstream object, specifying by a file mode flag that the file is being opened for reading only:

 fstream afile;   afile.open("students.dat", ios::in); 

The following statement uses the ifstream constructor to open a file for reading:

 ifstream infile ("students.dat"); 

You could accomplish the same purpose using the fstream constructor, specifying in the second argument the file mode flag that the file is being opened for reading only:

 fstream afile ("students.dat", ios::in); 

Opening a File for Reading and Writing

You can use the fstream object to open a file for reading and for writing. You cannot use either the ofstream or ifstream object for this purpose, as an ofstream object cannot be used to read files, and an ifstream object cannot be used to write to files.

The following code fragment uses the open member function of the fstream object for this purpose:

 fstream afile;  afile.open("students.dat", ios::in  ios::out); 

Alternatively, you can use the two-argument fstream constructor:

 fstream afile ("students.dat", ios::in  ios::out); 

Both alternatives use the bitwise or operator () discussed in the earlier section Second Argument ”File Mode to combine the file mode flags for input and output.

Note  

Combining the ios::in and ios::out flags changes expected defaults. The ios::out flag by itself causes an existing file to be overwritten, and the ios::in flag by itself requires that the file already exist. However, when the ios::in and ios::out files are used together, the file s existing contents are preserved, and the file will be created if it does not already exist.

Checking if the File Was Opened

You should not assume that a file was successfully opened with the open member function or the constructor. There are several reasons why the file may not have been successfully opened. If the file was not successfully opened, but your code casually assumes it was and attempts to read from, or write to, the file, errors may occur.

The primary difference between opening a file for reading and for writing is that while you can write to a file that does not exist ”the operating system simply creates the file ”you cannot read from a file unless it already exists. Therefore, you should check if the file was opened successfully for reading before you attempt to read it.

If the file could not be opened for reading, then the value of the ifstream object that called the open function is NULL. As you may recall from Chapter 11, NULL is a constant defined in several standard library files whose value is zero.

Alternatively, if the file could not be opened for reading, then the ifstream object s fail member function returns true, which is the fail function s return value if a file operation, in this case attempting to open a file, was not successful.

The following code illustrates the use of both checking if the ifstream object used to call the open function is NULL and whether the ifstream object s fail member function returns true:

 #include <fstream> #include <iostream> using namespace std; int main () {  ifstream infile;  infile.open("students.dat");  cout << "(infile) = " << infile << endl;  cout << "(infile.fail()) = " << infile.fail() << endl;  return 0; } 

If the students.dat file does not yet exist, the output would be

 (infile) = 00000000 (infile.fail()) = 1 

However, if there was a file named students.dat in the same directory as your program, then the output would be

 (infile) = 0012FE40 (infile.fail()) = 0 

The value, 0012FE40, is the address of the ifstream variable infile, and of course could be different if you run this program.

Unlike an ifstream object, an ofstream object that attempts to open a file that does not yet exist is not NULL, and its fail member function would return false, because the operating system will create the file if it does not already exist. However, opening a file for writing is not always successful. For example, before you run the following program, create a file named students.dat in the same directory as your program but, through its properties, check read only:

 #include <fstream> #include <iostream> using namespace std; int main () {  ofstream outfile;  outfile.open("students.dat");  cout << "(outfile) = " << outfile << endl;  cout << "(outfile.fail()) = " << outfile.fail() << endl;  return 0; } 

The following output reflects that the ofstream object is NULL, and its fail function returns true, because you cannot open for writing a file that is read only.

 (outfile) = 00000000  (outfile.fail()) = 1 

If you cannot open a file for reading or writing, then you do not want to proceed to execute the code that reads from, or writes to, the file. Instead, you may want to stop execution of the function, as in the following code fragment:

 ifstream infile;  infile.open("students.dat");  if (infile == NULL)  {  cout << "Error in opening file for reading";  return 0;  }  // code to read from file 
Note  

For purposes of brevity and avoiding repetitive code, some of the following code in this chapter omits checking if a file was opened successfully.




C++ Demystified(c) A Self-Teaching Guide
C++ Demystified(c) A Self-Teaching Guide
ISBN: 72253703
EAN: N/A
Year: 2006
Pages: 148

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net