53. File I/O
Definition
File I/O (Input/Output) is the mechanism for reading and writing data from/to files on the filesystem. C++ provides consistent stream classes for various data sources: files, strings, and even networks. This stream framework uses the same >> and << operators as cin and cout, so the interface used is very familiar.
Main classes: ifstream (input), ofstream (output), and fstream (both).
ifstream — Reading Files
#include <iostream>
#include <ifstream>
#include <string>
using namespace std;
int main() {
ifstream file("data.txt");
if (!file.is_open()) {
cerr << "Failed to open file!" << endl;
return 1;
}
// Read line by line
string line;
while (getline(file, line)) {
cout << line << endl;
}
file.close();
return 0;
}
Code Explanation
ifstream file("name.txt")opens a file for reading.is_open()checks whether the file was opened successfully.getline(file, line)reads one line from the file into a string.close()closes the file — done automatically when the destructor is called.
ofstream — Writing Files
#include <iostream>
#include <ofstream>
#include <string>
using namespace std;
int main() {
ofstream file("output.txt");
if (!file.is_open()) {
cerr << "Failed to create file!" << endl;
return 1;
}
file << "Name: Mike" << endl;
file << "Age: 25" << endl;
file << "City: Chicago" << endl;
// Write with formatting
for (int i = 1; i <= 5; i++) {
file << "Line " << i << ": " << i * 10 << endl;
}
file.close();
cout << "File written successfully!" << endl;
return 0;
}
Code Explanation
ofstream file("output.txt")creates a new file or overwrites an existing one.- The
<<operator is used likecoutto write to the file. endlor"\n"for newlines.
fstream — Read and Write
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
// Create the file first
{
ofstream create("config.txt");
create << "mode=debug" << endl;
create << "port=8080" << endl;
create << "host=localhost" << endl;
}
// Read and modify
fstream file("config.txt", ios::in | ios::out);
if (!file.is_open()) {
cerr << "Failed to open file!" << endl;
return 1;
}
// Read all contents
string line;
cout << "File contents:" << endl;
while (getline(file, line)) {
cout << line << endl;
}
// Back to the start of the file
file.clear(); // clear flags
file.seekg(0);
// Find and replace the port
while (getline(file, line)) {
if (line.find("port=") != string::npos) {
streampos pos = file.tellg();
file.seekp(pos - static_cast<streamoff>(line.length()));
file << "port=9090";
break;
}
}
file.close();
return 0;
}
Code Explanation
fstreamwithios::in | ios::outopens a file for reading and writing.seekg()moves the get (read) position.seekp()moves the put (write) position.tellg()returns the current position.clear()removes error flags after reaching EOF.
File Modes
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
// ios::out — write (default, overwrites)
ofstream out1("file1.txt");
out1 << "New data" << endl;
out1.close();
// ios::app — append at the end of the file
ofstream out2("file1.txt", ios::app);
out2 << "Added" << endl;
out2.close();
// ios::in — read
ifstream in("file1.txt");
string line;
cout << "Contents of file1.txt:" << endl;
while (getline(in, line)) {
cout << line << endl;
}
in.close();
// ios::binary — binary mode
// Write binary data
struct Biodata {
char name[50];
int age;
double gpa;
};
Biodata student = {"Mike Johnson", 21, 375};
ofstream outBin("biodata.bin", ios::binary);
outBin.write(reinterpret_cast<char*>(&student), sizeof(Biodata));
outBin.close();
// Read binary data
Biodata studentRead;
ifstream inBin("biodata.bin", ios::binary);
inBin.read(reinterpret_cast<char*>(&studentRead), sizeof(Biodata));
inBin.close();
cout << "\nData biner:" << endl;
cout << "Name: " << studentRead.name << endl;
cout << "Age: " << studentRead.age << endl;
cout << "GPA: " << studentRead.gpa << endl;
return 0;
}
Code Explanation
| Mode | Function |
|---|---|
ios::in |
Read |
ios::out |
Write (overwrite) |
ios::app |
Append at the end |
ios::binary |
Binary mode (no encoding) |
ios::trunc |
Clear file contents when opened |
ios::ate |
Move to end of file on open |
getline with Files
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
int main() {
// Create a sample file
{
ofstream out("names.txt");
out << "Mike,John,Anna" << endl;
out << "Dana,Eric,Frank" << endl;
}
// Read with a comma delimiter
ifstream file("names.txt");
string line;
while (getline(file, line)) {
stringstream ss(line);
string name;
while (getline(ss, name, ',')) {
cout << "Name: " << name << endl;
}
}
file.close();
return 0;
}
Code Explanation
getline(file, line, delimiter)reads up to a specific delimiter.stringstreamsplits a string based on a delimiter.
Binary File I/O
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
struct Record {
int id;
double grade;
};
int main() {
// Write several records
vector<Record> data = {
{1, 85.5}, {2, 92.0}, {3, 78.5}, {4, 95.0}
};
ofstream outFile("records.bin", ios::binary);
size_t count = data.size();
outFile.write(reinterpret_cast<const char*>(&count), sizeof(size_t));
outFile.write(reinterpret_cast<const char*>(data.data()), count * sizeof(Record));
outFile.close();
// Read the records
ifstream inFile("records.bin", ios::binary);
size_t readCount;
inFile.read(reinterpret_cast<char*>(&readCount), sizeof(size_t));
vector<Record> readData(readCount);
inFile.read(reinterpret_cast<char*>(readData.data()), readCount * sizeof(Record));
inFile.close();
cout << "Data that was read:" << endl;
for (const auto& rec : readData) {
cout << "ID: " << rec.id << ", Grade: " << rec.grade << endl;
}
return 0;
}
Code Explanation
write()writes a block of binary data to the file.read()reads a block of binary data from the file.reinterpret_cast<char*>is needed because streams work with bytes (char).
stringstream — String Manipulation
istringstream — Reading from a String
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main() {
string data = "Mike 25 3.75";
istringstream iss(data);
string name;
int age;
double gpa;
iss >> name >> age >> gpa;
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
cout << "GPA: " << gpa << endl;
return 0;
}
ostringstream — Writing to a String
#include <iostream>
#include <sstream>
#include <iomanip>
using namespace std;
int main() {
ostringstream oss;
oss << "Annual Report" << endl;
oss << string(30, '=') << endl;
oss << fixed << setprecision(2);
oss << "Pendapatan: $ " << 12345678.9 << endl;
oss << "Pengeluaran: $ " << 8765432.1 << endl;
oss << "Laba: $ " << (12345678.9 - 8765432.1) << endl;
string result = oss.str();
cout << result;
return 0;
}
Code Explanation
istringstreamreads from a string using the>>operator.ostringstreamwrites to a string using the<<operator.str()returns the result as a string.
Case Study: Log File
#include <iostream>
#include <fstream>
#include <string>
#include <ctime>
#include <sstream>
using namespace std;
class Logger {
ofstream logFile;
public:
Logger(const string& filename) {
logFile.open(filename, ios::app);
}
void log(const string& level, const string& message) {
time_t now = time(nullptr);
tm* ltm = localtime(&now);
ostringstream timestamp;
timestamp << setfill('0') << setw(2) << ltm->tm_hour << ":"
<< setw(2) << ltm->tm_min << ":"
<< setw(2) << ltm->tm_sec;
logFile << "[" << timestamp.str() << "] "
<< "[" << level << "] "
<< message << endl;
cout << "[" << timestamp.str() << "] "
<< "[" << level << "] "
<< message << endl;
}
~Logger() {
logFile.close();
}
};
int main() {
Logger logger("app.log");
logger.log("INFO", "application started");
logger.log("INFO", "Database connection successful");
logger.log("WARNING", "Memory usage high: 85%");
logger.log("ERROR", "Failed to send email");
logger.log("INFO", "application done");
return 0;
}
Case Study: CSV Reader
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
using namespace std;
struct Student {
string name;
int age;
double gpa;
};
vector<Student> readCSV(const string& filename) {
vector<Student> data;
ifstream file(filename);
string line;
getline(file, line); // skip the header
while (getline(file, line)) {
stringstream ss(line);
string name, umurStr, ipkStr;
getline(ss, name, ',');
getline(ss, umurStr, ',');
getline(ss, ipkStr, ',');
data.push_back({name, stoi(umurStr), stod(ipkStr)});
}
return data;
}
int main() {
// Create a CSV file
{
ofstream out("student.csv");
out << "name,age,gpa" << endl;
out << "Mike,20,3.5" << endl;
out << "John,21,3.8" << endl;
out << "Anna,19,3.2" << endl;
}
// Read the CSV
vector<Student> data = readCSV("student.csv");
cout << "Student data:" << endl;
for (const auto& s : data) {
cout << s.name << " | Age: " << s.age << " | GPA: " << s.gpa << endl;
}
return 0;
}
Case Study: Config File Parser
#include <iostream>
#include <fstream>
#include <sstream>
#include <map>
#include <string>
using namespace std;
map<string, string> parseConfig(const string& filename) {
map<string, string> config;
ifstream file(filename);
string line;
while (getline(file, line)) {
// Skip comments and empty lines
if (line.empty() || line[0] == '#') continue;
// Find the '=' separator
size_t pos = line.find('=');
if (pos != string::npos) {
string key = line.substr(0, pos);
string value = line.substr(pos + 1);
// Trim spaces
key.erase(0, key.find_first_not_of(" \t"));
key.erase(key.find_last_not_of(" \t") + 1);
value.erase(0, value.find_first_not_of(" \t"));
value.erase(value.find_last_not_of(" \t") + 1);
config[key] = value;
}
}
return config;
}
int main() {
// Create a config file
{
ofstream out("app.conf");
out << "# Application configuration" << endl;
out << "app_name = MyProgram" << endl;
out << "version = 1.0.0" << endl;
out << "debug = true" << endl;
out << "port = 8080" << endl;
out << "host = localhost" << endl;
}
auto config = parseConfig("app.conf");
cout << "Konfigurasi:" << endl;
for (const auto& [key, value] : config) {
cout << " " << key << " = " << value << endl;
}
return 0;
}
Error Handling
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
ifstream file("missing.txt");
if (!file) {
cerr << "Error: file not found" << endl;
return 1;
}
// Check the stream state
string line;
while (file.good()) {
getline(file, line);
if (!file.eof()) {
cout << line << endl;
}
}
// Check the various error states
if (file.bad()) cerr << "Critical I/O error" << endl;
if (file.fail()) cerr << "Logical error" << endl;
if (file.eof()) cout << "EOF reached" << endl;
file.close();
return 0;
}
Code Explanation
good()— everything is OK.eof()— end of file reached.fail()— logical error (format mismatch, file not found).bad()— critical I/O error (disk failure).
File I/O Tips
- Always check
is_open()after opening a file - Use RAII — let the destructor close the file
- Use
getline()to read full lines (not>>) - For binary files, always use
ios::binary - Use
clear()after an operation that may fail - Prefer
stringstreamfor complex string manipulation
Summary
File I/O in C++ uses a consistent stream model. ifstream for reading, ofstream for writing, fstream for both. File modes determine how a file is accessed. stringstream allows string manipulation like a file. Error handling is very important — always check whether I/O operations succeeded.