C++ Files
Introduction to File Handling
File handling in C++ is performed using the <fstream>
library, which provides three main classes:
- std::ofstream
: For creating and writing to files.
- std::ifstream
: For reading from files.
- std::fstream
: For both reading and writing.
Common operations include creating, opening, reading, writing, appending, seeking, and closing. Streams automatically close when they go out of scope (RAII).
Writing to a File
Use std::ofstream
to create and write to files. By default, opening an ofstream
with just a filename uses ios::out | ios::trunc
, which truncates (overwrites) the file if it exists. Use ios::app
to append instead.
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ofstream myFile("example.txt"); // default: ios::out | ios::trunc
if (myFile) {
myFile << "Hello, file!";
// myFile.close(); // optional; destructor closes automatically
cout << "File written successfully.";
} else {
cout << "Unable to open file.";
}
return 0;
}
File written successfully.
Reading from a File
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
ifstream myFile("example.txt");
string line;
if (myFile) {
while (getline(myFile, line)) {
cout << line << '\n';
}
// myFile.close(); // optional; destructor closes automatically
} else {
cout << "Unable to open file.";
}
return 0;
}
Hello, file!
Appending to a File
To append to an existing file, open it with the ios::app
flag (append-only).
ofstream myFile("example.txt", ios::app);
myFile << "\nNew line";
// myFile.close(); // optional
Seeking (Moving the Read/Write Position)
You can move the file position indicators to read/write at arbitrary locations:
- seekp
/ tellp
for the output (put) position
- seekg
/ tellg
for the input (get) position
#include <fstream>
using namespace std;
int main() {
fstream f("example.txt", ios::in | ios::out);
if (!f) return 1;
f.seekp(0, ios::end); // go to end
f << "\nAppended via seekp";
f.seekg(0, ios::beg); // go to beginning
// ... read from start
}
Text vs Binary Mode
Open non-text data with ios::binary
, especially on Windows where text mode may translate newlines:
- Text mode may translate \n
to \r\n
on write and back on read.
- Binary mode performs no translation.
#include <fstream>
#include <vector>
using namespace std;
int main() {
vector<unsigned char> bytes = {0xDE, 0xAD, 0xBE, 0xEF};
ofstream out("data.bin", ios::binary);
out.write(reinterpret_cast<const char*>(bytes.data()), bytes.size());
}
File Modes
Flag | Description |
---|---|
ios::in | Open for reading |
ios::out | Open for writing (implies truncation unless combined with ios::app or paired with ios::in/ios::ate) |
ios::app | Append on every write (seek to end before each write) |
ios::trunc | Truncate file to zero length on open (if it exists) |
ios::binary | Open in binary mode (no text translation) |
ios::ate | Open and seek to end immediately (not append-only; you can still seek elsewhere) |
Error Handling & Exceptions
Check stream state after operations (if (!stream)
) or enable exceptions for critical I/O:
Set exceptions and handle failures with try/catch:
#include <fstream>
#include <iostream>
using namespace std;
int main() {
ofstream out;
out.exceptions(ios::failbit | ios::badbit);
try {
out.open("log.txt", ios::app);
out << "entry\n";
} catch (const ios_base::failure& e) {
cerr << "I/O error: " << e.what() << '\n';
}
}
Best Practices
- Rely on RAII: streams close automatically when they go out of scope; call close()
early only if you need to reopen or to check close errors explicitly.
- Prefer '\n'
over std::endl
unless you need to flush.
- Choose modes deliberately: ofstream
alone truncates; use ios::app
to append or pair ios::out
with ios::in
/ios::ate
to avoid truncation.
- Use ios::binary
for non-text data.
- Always verify operations succeeded (check stream state or use exceptions).