C++ file I/O | ifstream, ofstream, and binary reads/writes

C++ file I/O | ifstream, ofstream, and binary reads/writes

이 글의 핵심

Hands-on guide to ofstream/ifstream, ios::app and ios::binary, checking is_open, line-by-line reading, and when to use filesystem paths for Unicode names.

Writing files (ofstream)

#include <fstream>
#include <iostream>
using namespace std;

int main() {
    ofstream file("output.txt");
    
    if (!file.is_open()) {
        cout << "Failed to open file" << endl;
        return 1;
    }
    
    file << "Hello, World!" << endl;
    file << "C++ file I/O" << endl;
    
    file.close();
    cout << "File saved" << endl;
    
    return 0;
}

Reading files (ifstream)

#include <fstream>
#include <iostream>
#include <string>
using namespace std;

int main() {
    ifstream file("input.txt");
    
    if (!file.is_open()) {
        cout << "Failed to open file" << endl;
        return 1;
    }
    
    string line;
    while (getline(file, line)) {
        cout << line << endl;
    }
    
    file.close();
    
    return 0;
}

File modes

// overwrite
ofstream file1("file.txt");

// append
ofstream file2("file.txt", ios::app);

// read
ifstream file3("file.txt");

// read + write
fstream file4("file.txt", ios::in | ios::out);

// binary
ofstream file5("file.bin", ios::binary);

Practical examples

Example 1: Read CSV

#include <fstream>
#include <sstream>
#include <vector>
#include <iostream>
using namespace std;

struct Student {
    string name;
    int age;
    double score;
};

vector<Student> readCSV(const string& filename) {
    vector<Student> students;
    ifstream file(filename);
    
    if (!file.is_open()) {
        cout << "Failed to open file" << endl;
        return students;
    }
    
    string line;
    getline(file, line);  // skip header
    
    while (getline(file, line)) {
        stringstream ss(line);
        Student s;
        string token;
        
        getline(ss, s.name, ',');
        getline(ss, token, ',');
        s.age = stoi(token);
        getline(ss, token, ',');
        s.score = stod(token);
        
        students.push_back(s);
    }
    
    file.close();
    return students;
}

int main() {
    vector<Student> students = readCSV("students.csv");
    
    for (const auto& s : students) {
        cout << s.name << ", age " << s.age << ", score " << s.score << endl;
    }
    
    return 0;
}

CSV parsing appears in many real systems.

Example 2: Log file

#include <fstream>
#include <iostream>
#include <ctime>
using namespace std;

class Logger {
private:
    ofstream logFile;
    
    string getCurrentTime() {
        time_t now = time(0);
        char buf[80];
        strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&now));
        return string(buf);
    }
    
public:
    Logger(const string& filename) {
        logFile.open(filename, ios::app);
    }
    
    ~Logger() {
        if (logFile.is_open()) {
            logFile.close();
        }
    }
    
    void info(const string& message) {
        logFile << "[" << getCurrentTime() << "] [INFO] " 
                << message << endl;
    }
    
    void error(const string& message) {
        logFile << "[" << getCurrentTime() << "] [ERROR] " 
                << message << endl;
    }
};

int main() {
    Logger logger("app.log");
    
    logger.info("program start");
    logger.info("loading data...");
    logger.error("file not found");
    logger.info("program exit");
    
    return 0;
}

Logging to files is essential in most applications.

Example 3: Binary struct I/O

#include <fstream>
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;

struct GameSave {
    int level;
    int score;
    int lives;
    char playerName[50];
};

void saveGame(const string& filename, const GameSave& save) {
    ofstream file(filename, ios::binary);
    file.write(reinterpret_cast<const char*>(&save), sizeof(GameSave));
    file.close();
    cout << "Game saved" << endl;
}

GameSave loadGame(const string& filename) {
    GameSave save{};
    ifstream file(filename, ios::binary);
    
    if (file.is_open()) {
        file.read(reinterpret_cast<char*>(&save), sizeof(GameSave));
        file.close();
        cout << "Game loaded" << endl;
    }
    
    return save;
}

int main() {
    GameSave save{};
    save.level = 10;
    save.score = 5000;
    save.lives = 3;
    strcpy(save.playerName, "Player1");
    
    saveGame("save.dat", save);
    
    GameSave loaded = loadGame("save.dat");
    cout << "level: " << loaded.level << endl;
    cout << "score: " << loaded.score << endl;
    cout << "lives: " << loaded.lives << endl;
    cout << "name: " << loaded.playerName << endl;
    
    return 0;
}

Binary serialization of POD-like structs—mind endianness and versioning in production.

Common pitfalls

Pitfall 1: Not checking open

Symptom: Empty reads on missing files.

Cause: Skipping is_open().

ifstream file("nonexistent.txt");
if (!file.is_open()) {
    cerr << "Failed to open file" << endl;
    return 1;
}

Pitfall 2: Forgetting to flush/close

Symptom: Truncated output on crash.

Fix: close(), or rely on scope; understand flush when mixing streams.

{
    ofstream file("output.txt");
    file << "data";
}

Pitfall 3: Text vs binary

Symptom: Corrupt numeric data on Windows.

Fix: Open with ios::binary for raw structs.

ofstream file("data.bin", ios::binary);

FAQ

Q1: Test if a file exists?

A: Try opening it or use std::filesystem::exists.

bool fileExists(const string& filename) {
    ifstream file(filename);
    return file.is_open();
}

Q2: Read entire file into a string?

A:

#include <fstream>
#include <sstream>

string readFile(const string& filename) {
    ifstream file(filename);
    stringstream buffer;
    buffer << file.rdbuf();
    return buffer.str();
}

Q3: File size?

A: seekg/tellg (binary mode avoids text quirks).

ifstream file("file.txt", ios::binary);
file.seekg(0, ios::end);
size_t size = file.tellg();
file.seekg(0, ios::beg);

Q4: Large files?

A: Read line by line or in chunks.

ifstream file("large.txt");
string line;
while (getline(file, line)) {
}

Q5: Non-ASCII paths?

A: Use std::filesystem::path and wide APIs where required on Windows.

#include <filesystem>
namespace fs = std::filesystem;

fs::path p = U"path/with/unicode";  // platform-specific helpers as needed

Q6: Multiple files at once?

A: Use separate stream objects.

ifstream file1("input1.txt");
ifstream file2("input2.txt");
ofstream output("output.txt");

  • C++ file operations deep dive
  • C++ file I/O basics
  • C++ operator overloading

Practical tips

Debugging

  • Enable warnings.
  • Reproduce with tiny files.

Performance

  • Profile before optimizing.

Code review

  • Follow team conventions.

Production checklist

Before coding

  • Right tool?
  • Maintainable?
  • Meets I/O requirements?

While coding

  • Warnings cleared?
  • Edge cases covered?

At review

  • Intent clear?
  • Tests sufficient?

Keywords

C++, file I/O, ifstream, ofstream, fstream


  • C++ series
  • C++ Adapter Pattern
  • C++ ADL |
  • C++ Aggregate Initialization |