-
Notifications
You must be signed in to change notification settings - Fork 134
Input Output
The code examples you've seen so far in this tutorial have used the cout object, which automatically writes to the screen. However, one often wishes to write to files for longer-term storage. In addition, one often finds it necessary to read from existing files, e.g. to obtain data necessary for a computation.
There are two fundamental types of file-based input/output (I/O): formatted and unformatted. Formatted means that the data is written to/read from the file as integers, doubles, characters, etc., while unformatted means that the data is handled as raw bytes and (perhaps) interpreted later. Formatted files are convenient because they can be read by simple text editors like vi or emacs (or even Microsoft Word!), while unformatted files appear as gibberish to such programs. On the other hand, unformatted files are usually much more compact than formatted files, and they store numerical data with no additional loss of precision. In this section, we focus on formatted I/O as it's easier to learn and will get you started.
To use the functionality described here in a C++ program, you must use the standard I/O header file:
#include <iostream>
#include <fstream> // necessary for formatted I/O
However, it is also possible to make use of older (but often more convenient) C-language output:
#include <cstdio>
which provides declarations for functions like printf() that will be described below.
In C++-based I/O, writing to or reading from files involves special objects called "streams" of type "ifstream" (input stream) or "ofstream" (output stream). Three special C++ streams are:
cin | Stream for input to a program. This can be keyboard input or input from a "<" redirect, for example. |
cout | Stream for output from a program. This can be to the screen or output from a ">" redirect, for example. |
cerr | Stream for error or diagnostic information. |
In C-style I/O, the corresponding streams "stdin", "stdout", and "stderr" are of the type "FILE *".
A nice Wikipedia page on standard streams exists
Before you can read or write data, you must first open the desired file stream. If you intend only to read from a given file, the simplest approach declare the stream to be of type “ifstream” and including the name of the file with the declaration:
ifstream my_input("data_file");
// Do something with the file here
my_input.close();
If you intend only to write to the file, use “ofstream” instead of “ifstream”. Alternatively, the more general approach is to declare the access mode explicitly:
ifstream my_input("data_file", ios::out | ios::app);
// Do something with the file here
my_input.close();
The name of the file stream is “my_input”, while the physical file is “data_file”. The “ios::out | ios::app” indicates that the file is opened for output, and we will write all new data starting at the end of the file (“append”). Selected C++ access modes are:
ios::in | Open the file for reading. |
ios::out | Create the file for writing. |
ios::ate | Set the initial position at the end of the file. |
ios::app | All writing occurs at the end of the file (“append”). |
ios::trunc | Create a new file for read/write. If the file already exists, delete (“truncate”) its contents. |
fopen() | Open a file for reading and/or writing data. |
fclose() | Close an open file stream. |
#include <cstdio>
FILE *my_input;
my_input = fopen("data_file", "r");
// Do something with the file here
fclose(my_input);
The name of the file stream is “my_input”, while the physical file is “data_file”. The “r” argument (called the “mode”) to fopen() indicates that you will only be reading data from the file. (If you try to write to the file, you'll get an error.) Other common modes:
r | Open the file for reading. |
w | Create the file for writing. |
a | Open an existing file for writing, starting at the end of the file ("append"). |
r+ | Open an existing file for read/write. |
w+ | Create a new file for read/write. |
a+ | Open an existing file for read/write, starting at the end of the file. |
Some examples of commonly used control characters include:
%d | Signed integer. |
%u | Unsigned integer. |
%f | Floating-point number. |
%e | Scientific notation with lower-case "e". |
%E | Scientific notation with upper-case "E". |
%s | String. |
%c | Character. |
%3d | Use three digits for integers, with spaces for leading zeroes. |
%03d | Use three digits for integers, including leading zeroes, e.g. "007". |
%3d | Print a 20-digit floating point number, with 12 digits to the right of the decimal point. |
my_input >> natom >> energy;
Similarly, one may read from the keyboard using the “cin” stream.
### C Style
There are numerous ways to read data from a file stream, but we'll focus here on the fscanf() function, which works very similarly to fprintf():
```c
int natom;
double energy;
fscanf(my_input, "%d %lf", &natom, &energy);
This function reads from the current position of the stream “my_input” an integer and a double, placing the results into the variables natom and energy, respectively. (Note that, in order for the values of the variables to be changed, the addresses of natom and energy must be given to fscanf(). More on this in later sections of this tutorial.)
The control characters are much like those used with fprintf(), though field widths are not specified. Some common control characters:
%d | Signed integer. |
%f | Single-precision floating-point number. |
%lf | Double-precision floating-point number. |
%s | String. |
%c | Character. |