File Input/Output
File Streams
Standard streams are automatically opened. Other files must be opened explicitly. Files can be input streams (ifstream), output streams (ofstream), or either/both (fstream).
#include <fstream>
or
#include <ofstream>
#include <ifstream>
as needed.
Open
First a stream object must be declared.
ifstream input;
Then the stream can be attached to a named file
input.open(inFileName);
This assumes the file exists and is opened for reading only.
For output use
ofstream output;
output.open(outFileName);
This file will be emptied if it exists or created if it does not exist, and will be opened in write-only mode.
To open read/write use
fstream myfile;
myfile.open(myfileName);
Modifiers
We can control the characteristics of the file with modifiers
ios::in
open for input (read). Default for ifstream.ios::out
open for output (write). Default for ofstream.ios::binary
open as binary (not text)ios::app
appendios::trunc
if file exists, overwrite (default for ofstream)
Use a pipe (|) to combine them
ofstream myfile;
myfile.open("myfile.dat",ios::binary | ios::app);
Inquiring
All inquiry methods return a bool
(Boolean). To check whether a file is open
myfile.is_open()
To check whether a file opened for reading is at the end
myfile.eof()
To test for any error condition
myfile.good()
Close
Much of the time, it is not necessary to close a file explicitly. Files are automatically closed when execution terminates. If many files are opened, it is good practice to close them before the end of the run.
myfile.close();
Rewind
An open unit can be rewound. This places the file pointer back to the beginning of the file. The default is to rewind a file automatically when it is closed.
These are C-style functions and are in <cstdio>
.
rewind(mystream)
You can also seek to position 0
fseek(mystream,0,SEEK_SET)
where rewind
clears the end-of-file and error indicators, whereas fseek
does not.
Writing to a File
We write to a file much like to a standard stream. In this example, we assume that var1, var2, and var3 are arrays or vectors of length nlines
.
ofstream out("outfile.txt");
out<<"column1,column2,column3\n";
for (int i=0;i<nlines;++i) {
out<<var1[i]<<","<<var2[i]<<","<<var3[i]<<"\n';
}
Reading from a File
The extraction operator works on file objects as well as on cin:
#include <fstream>
#include <iostream>
int main() {
float var1, var2;
std::ifstream myfile("data.txt");
if (myfile.is_open()) {
while ( ! myfile.eof() ) {
myfile >> var1 >> var2;
std::cout<<var1<<" "<<var2<<"\n";
}
}
}
Although this method works, it has a number of drawbacks. As we learned for console IO, the extraction operator assumes the separator is whitespace. It can be thrown off when attempting to convert a string into a numerical type. It also is inflexible. We will discuss more advanced methods in the next chapter.
Exercise
Write a program that creates a file mydata.txt containing four rows consisting of
1 2 3
4 5 6
7 8 9
10 11 12
Either rewind or reopen the file and read the data back. Write a loop to add 1 to each value and print each row to the console. Note that if you choose to rewind, the file will have to be opened read/write. If you close it and reopen it, it will have to be reopened in write mode. You may use a statically-sized array for the data. In the next chapter we will learn a more flexible method of reading lines of files.
Example Solution
#include <iostream>
#include <fstream>
using namespace std;
int main() {
fstream myfile;
myfile.open("mydata.txt", ios::out);
for (int i=1; i<=12; ++i) {
myfile << i;
if (i%3==0) {
myfile << "\n";
} else {
myfile << " ";
}
}
myfile.close();
myfile.open("mydata.txt", ios::in);
int x[4][3];
if (myfile.is_open()) {
for (int i=0; i<4; ++i) {
myfile>>x[i][0]>>x[i][1]>>x[i][2];
}
} else {
cout<<"Unable to open file";
return 1;
}
for (int i=0; i<4; ++i) {
for (int j=0; j<3; ++j) {
x[i][j]++;
}
}
for (int i=0; i<4; ++i) {
for (int j=0; j<3; ++j) {
cout << x[i][j] << " ";
}
cout << "\n";
}
}