Skip to content
C++ Better Explained
Go back
How to Append to a File in C++ (std::ios::app)

How to Append to a File in C++

Short answer: pass std::ios::app when you open the stream. Without it, ofstream wipes the file the moment it opens.

std::ofstream file("log.txt", std::ios::app);
file << "another line\n";

The Default Behaviour That Catches Everyone

This innocent-looking code destroys your file:

std::ofstream file("log.txt");   // file is now EMPTY
file << "new entry\n";

ofstream defaults to std::ios::out | std::ios::trunc. Truncate means “set the length to zero” — and it happens at open time, before you write anything. If your program crashes on the next line, the file is already gone.

This is the single most common file-handling mistake in C++, and it is silent: no error, no warning, just an empty file.

Appending Correctly

#include <iostream>
#include <fstream>

int main() {
    std::ofstream file("log.txt", std::ios::app);

    if (!file) {
        std::cerr << "Could not open log.txt\n";
        return 1;
    }

    file << "Program started\n";
    file << "Value: " << 42 << '\n';
}

Run it three times and you get six lines, not two. The file is created automatically if it does not exist yet.

Learning C++ properly? The C++ Better Explained Ebook covers file handling, strings and the STL in plain English — 87 pages, just $19.

app vs ate vs trunc

FlagWhat it does
std::ios::truncEmpties the file on open (the ofstream default)
std::ios::appEvery write goes to the end, always
std::ios::ateSeeks to the end on open, but you can move elsewhere
std::ios::inOpen for reading
std::ios::outOpen for writing
std::ios::binaryNo text translation of line endings

The app versus ate distinction matters more than it looks:

// app — the seek is ignored, text still lands at the end
std::ofstream a("f.txt", std::ios::app);
a.seekp(0);
a << "X";          // appended at the end

// ate — the seek works, and this OVERWRITES the first byte
std::ofstream b("f.txt", std::ios::ate);
b.seekp(0);
b << "X";          // overwrites position 0

Use app for logs. Use ate only when you genuinely intend to move around inside an existing file.

Combining Flags

Flags are bit masks, combined with |:

// read and append
std::fstream f("data.txt", std::ios::in | std::ios::app);

// append in binary mode
std::ofstream b("data.bin", std::ios::app | std::ios::binary);

A Small Logging Helper

#include <fstream>
#include <string>
#include <ctime>

void log(const std::string& message) {
    std::ofstream file("app.log", std::ios::app);
    if (!file) return;

    std::time_t now = std::time(nullptr);
    char stamp[20];
    std::strftime(stamp, sizeof(stamp), "%Y-%m-%d %H:%M:%S",
                  std::localtime(&now));

    file << "[" << stamp << "] " << message << '\n';
}

int main() {
    log("Program started");
    log("Something happened");
}

Opening and closing per call is slightly slower but much safer — the data is flushed to disk each time, so a crash does not lose your log.

Making Sure Data Is Written

Stream output is buffered. If you keep one stream open for a long time, force a flush at the points that matter:

std::ofstream file("log.txt", std::ios::app);
file << "important\n";
file.flush();            // or: file << std::endl;

std::endl writes a newline and flushes, which is why it is slower than '\n' in loops. Use '\n' for ordinary output and flush deliberately when you need durability.

Checking a Write Succeeded

Writes can fail — a full disk, a read-only file, a vanished network drive:

std::ofstream file("log.txt", std::ios::app);
file << "data\n";

if (!file) {
    std::cerr << "Write failed\n";
}

The stream stays in a failed state once something goes wrong, so a single check after a batch of writes is usually enough.

Quick Reference

GoalCode
Append textstd::ofstream f("x.txt", std::ios::app);
Overwrite the filestd::ofstream f("x.txt");
Read and appendstd::fstream f(p, std::ios::in | std::ios::app);
Append binarystd::ios::app | std::ios::binary
Force to diskf.flush();

Take Your C++ Further

If you want file handling and the rest of C++ explained properly rather than one snippet at a time, the C++ Better Explained Ebook covers the fundamentals in plain English. Just $19.

👉 Get the C++ Better Explained Ebook — $19


📋

Free Download: The 10 Mistakes Every C++ Beginner Makes

A free 1-page checklist that shows the exact traps that slow down every C++ beginner — so you can avoid them from day one.

🔒 No spam. Unsubscribe anytime.


Share this post on:

Written by

Sahil Bora

Software Engineer. Author and creator of C++ Better Explained.


Previous Post
Menu Driven Program in C++: Build a Clean Interactive Menu
Next Post
C++ Input Validation: Handling Bad cin Input Without Crashing

Keep Learning