Skip to content
Laviyx Learn

Try

C++ course menu

C++ File Handling: Reading and Writing Files with fstream

Learn file I/O in C++: writing with std::ofstream, reading line by line with std::ifstream and getline, appending, checking that a file opened, parsing CSV data, reading numbers, binary files, and working with paths using std::filesystem.

Advanced14 min readUpdated
On this page

Programs often need to save data and load it later: settings, logs, reports, scores. C++ reads and writes files with file streams from <fstream>, which work just like std::cout and std::cin:

ClassUse
std::ofstreamWrite to a file ("output file stream")
std::ifstreamRead from a file ("input file stream")
std::fstreamBoth read and write

Writing a file#

C++
#include <fstream>
#include <iostream>

int main() {
    std::ofstream out("scores.txt");
    if (!out) {
        std::cout << "Could not open the file\n";
        return 1;
    }

    out << "Asha 92\n";
    out << "Ravi 85\n";
    out << "Meera 78\n";

    std::cout << "Saved\n";
}   // out is closed automatically here
Output
Saved
  • Creating an std::ofstream opens the file, creating it if it does not exist and replacing its contents if it does.
  • << writes exactly as with std::cout.
  • The file is closed automatically when the stream object is destroyed (RAII), so calling close() is optional.

Reading line by line#

std::getline reads one line at a time, and returns a value that tests false at the end of the file:

C++
#include <fstream>
#include <iostream>
#include <string>

int main() {
    {
        std::ofstream out("notes.txt");
        out << "Buy milk\nCall Ravi\nFinish C++ lesson\n";
    }

    std::ifstream in("notes.txt");
    if (!in) {
        std::cout << "notes.txt not found\n";
        return 1;
    }

    std::string line;
    int number = 1;
    while (std::getline(in, line)) {
        std::cout << number++ << ". " << line << '\n';
    }
}
Output
1. Buy milk
2. Call Ravi
3. Finish C++ lesson

while (std::getline(in, line)) is the standard loop for reading text files. Avoid while (!in.eof()), which runs one extra time after the last line.

Reading values with >>#

>> reads whitespace-separated values and converts them, just like std::cin:

C++
#include <fstream>
#include <iostream>
#include <string>

int main() {
    {
        std::ofstream out("scores.txt");
        out << "Asha 92\nRavi 85\nMeera 78\n";
    }

    std::ifstream in("scores.txt");
    std::string name;
    int score = 0;
    int total = 0;
    int count = 0;

    while (in >> name >> score) {
        total += score;
        ++count;
    }
    std::cout << count << " students, average " << static_cast<double>(total) / count << '\n';
}
Output
3 students, average 85

Appending#

Open with std::ios::app to add to the end of a file instead of replacing it, which is what log files need:

C++
#include <fstream>
#include <iostream>
#include <string>

void log(const std::string& message) {
    std::ofstream out("app.log", std::ios::app);
    out << message << '\n';
}

int main() {
    std::ofstream("app.log");   // start with an empty file
    log("started");
    log("processing");
    log("finished");

    std::ifstream in("app.log");
    std::string line;
    while (std::getline(in, line)) std::cout << line << '\n';
}
Output
started
processing
finished
Mode flagMeaning
std::ios::inOpen for reading
std::ios::outOpen for writing (default for ofstream)
std::ios::appAppend every write to the end
std::ios::truncEmpty the file when opening
std::ios::binaryDo not translate line endings

Combine flags with |, for example std::ios::out | std::ios::app.

Parsing CSV data#

Comma-separated files are read line by line, then split with std::getline on a std::stringstream:

C++
#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <string>

int main() {
    {
        std::ofstream out("sales.csv");
        out << "region,amount\nNorth,1200\nSouth,800\nNorth,450\nEast,990\n";
    }

    std::ifstream in("sales.csv");
    std::string line;
    std::getline(in, line);   // skip the header row

    std::map<std::string, int> totals;
    while (std::getline(in, line)) {
        std::stringstream row(line);
        std::string region;
        std::string amount;
        std::getline(row, region, ',');
        std::getline(row, amount, ',');
        totals[region] += std::stoi(amount);
    }

    for (const auto& [region, total] : totals) {
        std::cout << region << ": " << total << '\n';
    }
}
Output
East: 990
North: 1650
South: 800

This simple approach does not handle quoted fields that contain commas; real-world CSV files with such data need a proper CSV library.

Checking for errors#

A stream that failed to open, or hit bad data, tests as false. Always check after opening. If you prefer exceptions, ask the stream to throw:

C++
#include <fstream>
#include <iostream>

int main() {
    std::ifstream in("does-not-exist.txt");
    if (!in.is_open()) {
        std::cout << "Could not open does-not-exist.txt\n";
    }

    std::ifstream strict;
    strict.exceptions(std::ifstream::failbit | std::ifstream::badbit);
    try {
        strict.open("does-not-exist.txt");
    } catch (const std::ios_base::failure&) {
        std::cout << "Exception: open failed\n";
    }
}
Output
Could not open does-not-exist.txt
Exception: open failed

std::filesystem: working with paths#

C++17's <filesystem> handles files and folders: checking existence, sizes, creating directories, listing contents and building paths portably:

C++
#include <filesystem>
#include <fstream>
#include <iostream>

namespace fs = std::filesystem;

int main() {
    fs::create_directories("reports/2026");
    fs::path file = fs::path("reports") / "2026" / "summary.txt";

    std::ofstream(file, std::ios::binary) << "Total: 5400\n";

    std::cout << std::boolalpha << fs::exists(file) << '\n';
    std::cout << file.filename().string() << ' ' << file.extension().string() << '\n';
    std::cout << fs::file_size(file) << " bytes\n";

    fs::remove_all("reports");
    std::cout << fs::exists("reports") << '\n';
}
Output
true
summary.txt .txt
12 bytes
false

The / operator joins path parts with the correct separator for the operating system.

The file is opened in binary mode so that its size is the same everywhere. In text mode, Windows writes each \n as two characters (\r\n), so the same text would take 13 bytes on Windows and 12 on macOS and Linux.

Common mistakes#

Practice#

Practice exercise

Write five words to words.txt, one per line: apple, kiwi, banana, fig, cherry. Then read the file back and print the longest word and the total number of characters.

Show solution
C++
#include <fstream>
#include <iostream>
#include <string>

int main() {
    {
        std::ofstream out("words.txt");
        for (const char* w : {"apple", "kiwi", "banana", "fig", "cherry"}) {
            out << w << '\n';
        }
    }

    std::ifstream in("words.txt");
    std::string word;
    std::string longest;
    std::size_t total = 0;
    while (std::getline(in, word)) {
        total += word.size();
        if (word.size() > longest.size()) longest = word;
    }
    std::cout << "Longest: " << longest << '\n';
    std::cout << "Characters: " << total << '\n';
}
Output
Longest: banana
Characters: 24

banana and cherry are both 6 letters; using > keeps the first one found.

Key takeaway#

Finished this lesson?