Skip to main content

    Lesson • Intermediate Track

    Files & Streams

    By the end of this lesson you'll be able to write data to a file, read it back line by line or token by token, choose the right file mode, and parse text in memory with std::stringstream — the same stream skills power files, the console, and strings in C++.

    What You'll Learn

    • Write text files with std::ofstream and the << operator
    • Read files back with std::ifstream, >>, and std::getline
    • Use std::fstream and file modes (ios::app, ios::binary)
    • Always check is_open() and detect end-of-file (EOF) correctly
    • Parse strings in memory with std::stringstream
    • Close files properly and rely on RAII

    💡 Real-World Analogy

    Think of a stream as a conveyor belt for characters. cout is a belt running out to your screen; cin is a belt running in from the keyboard. A file stream is the exact same belt — it just connects to a file on disk instead. Because every belt works the same way, the << ("push onto the belt") and >> ("take off the belt") operators you already know for the console work unchanged on files and on strings. Learn one, and you've learned all three.

    1. Writing a File with ofstream

    std::ofstream (output file stream) opens a file for writing. You give it a filename, then push data onto it with << — exactly like cout. The golden rule: always check is_open() first, because a wrong path or a read-only folder fails silently otherwise. Read this worked example, then run it locally and open scores.txt to see the result.

    Worked example: write a text file

    Runs on your own machine — online sandboxes may lack a writable filesystem. Read every comment.

    Try it Yourself »
    C++
    #include <iostream>
    #include <fstream>   // file streams live here: ofstream, ifstream, fstream
    using namespace std;
    
    int main() {
        // ofstream = "output file stream" -> opens a file for WRITING.
        // If the file does not exist it is created; if it exists it is OVERWRITTEN.
        ofstream out("scores.txt");
    
        // ALWAYS check the file actually opened before you use it.
        if (!out.is_open()) {
            cout << "Could not open scores.txt for writing" << endl;
            return 1;               
    ...

    2. Reading a File with ifstream

    std::ifstream (input file stream) opens a file for reading. You have two tools: std::getline(in, line) grabs a whole line at a time, while in >> value reads one whitespace-separated token and converts its type for you. Both return the stream itself, which becomes "false" at end-of-file (EOF) — so they're perfect loop conditions that stop on their own.

    Worked example: read a file two ways

    getline for whole lines vs >> for tokens. Run locally after Section 1.

    Try it Yourself »
    C++
    #include <iostream>
    #include <fstream>
    #include <string>
    using namespace std;
    
    int main() {
        // ifstream = "input file stream" -> opens a file for READING.
        ifstream in("scores.txt");
    
        if (!in.is_open()) {
            cout << "scores.txt not found" << endl;
            return 1;
        }
    
        // Pattern 1: read WHOLE LINES with getline.
        // getline(stream, line) returns the stream, which is "false" at end-of-file,
        // so the loop stops automatically when there is nothing left to read.
        s
    ...

    3. File Modes: app and binary

    By default ofstream overwrites a file. Pass a mode flag as the second argument to change that. std::ios::app means append — new writes go to the end and existing content is kept (ideal for log files). std::ios::binary writes raw bytes with no text formatting, which you need for .write()/.read() on structs. std::fstream opens a file for reading and writing at once.

    Worked example: append & binary modes

    ios::app keeps existing content; ios::binary copies raw bytes. Run locally.

    Try it Yourself »
    C++
    #include <iostream>
    #include <fstream>
    using namespace std;
    
    struct Point { int x; int y; };   // a fixed-size record (8 bytes here)
    
    int main() {
        // ios::app  -> APPEND. Writes go to the END; existing content is kept.
        ofstream log("log.txt", ios::app);
        log << "user logged in" << endl;   // added after whatever was already there
        log.close();
    
        // ios::binary -> write RAW BYTES, no text formatting / newline translation.
        Point p{3, 4};
        ofstream bout("point.bin", ios::bin
    ...

    Heads-up: binary files are not portable across machines — endianness and struct padding differ between architectures. For data you'll share, prefer a text format (CSV, JSON) or a serialization library.

    4. Parsing in Memory with stringstream

    A std::stringstream is a stream backed by a std::string instead of a file. std::istringstream lets you read a string with getline and >> (perfect for splitting a CSV line into fields); std::ostringstream lets you build a string with << and pull the result out with .str(). Because it's all in memory, it runs anywhere — so the exercises below work right here in the editor.

    Your turn. The program below is almost complete — fill in the blanks marked ___ using the // 👉 hints, then run it.

    🎯 Your turn: split a CSV line

    Fill in the ___ blanks, then check your output against the expected line.

    Try it Yourself »
    C++
    #include <iostream>
    #include <sstream>   // istringstream = "read a string as if it were a file"
    #include <string>
    using namespace std;
    
    int main() {
        // 🎯 YOUR TURN — fill in the blanks marked ___ then press "Try it Yourself".
        // No real file needed: istringstream lets us PRACTISE parsing in memory.
    
        string csv = "Alice,London,30";
    
        // istringstream wraps the string so we can use getline / >> on it.
        istringstream iss(csv);
    
        string name, city, ageText;
    
        // getline(str
    ...

    One more. This time you'll read numbers with >> and build a report string with ostringstream. Fill in the two blanks:

    🎯 Your turn: build a report string

    Append the total, then extract the finished string with .str().

    Try it Yourself »
    C++
    #include <iostream>
    #include <sstream>   // ostringstream builds a string; istringstream reads one
    #include <string>
    #include <vector>
    using namespace std;
    
    int main() {
        // 🎯 YOUR TURN — parse some numbers, then BUILD a report string.
    
        string data = "10 25 5";        // three numbers separated by spaces
        istringstream in(data);
    
        // Read tokens with >> (it splits on whitespace for you).
        int total = 0, n;
        vector<int> nums;
        while (in >> n) {
            nums.push_back(n);
      
    ...

    Common Errors (and the fix)

    • Not checking is_open(): if the path is wrong or the folder is read-only, the open fails silently and your writes vanish. Always guard with if (!stream.is_open()) { /* handle it */ } before reading or writing.
    • Mixing >> and getline: >> leaves the trailing newline in the buffer, so the next getline returns an empty line. After reading a number with >>, call in.ignore() (or std::ws) before getline.
    • Forgetting ios::binary: calling .write()/.read() in text mode lets newline translation corrupt your bytes on Windows. Open with ofstream out(name, ios::binary) for any non-text data.
    • Not closing / not relying on RAII: data sits in a buffer until the stream is flushed. If you read the file before the writer's close() (or before it goes out of scope), it can look empty. Call .close() or let the stream's scope end first.
    • Looping on !in.eof(): EOF is set after a failed read, so this processes the last line twice. Loop on the read itself instead: while (getline(in, line)) or while (in >> x).

    📋 Quick Reference

    TaskCode
    Open file to writeofstream out("f.txt");
    Open file to readifstream in("f.txt");
    Read & writefstream io("f.txt");
    Append modeofstream(f, ios::app)
    Binary modeifstream(f, ios::binary)
    Check it openedif (in.is_open())
    Read a linegetline(in, line)
    Read a tokenin >> word
    Split on a chargetline(ss, f, ',')
    Build a stringoss << x; oss.str()
    Close the filestream.close();

    Frequently Asked Questions

    Q: Why does my online program say it can't open or find the file?

    Many online compilers (including this one) run in a sandbox with no writable or persistent filesystem, so ofstream may fail and a file you 'wrote' won't exist on the next run. That's exactly why the practice exercises here use std::stringstream, which works entirely in memory. The file examples run perfectly on your own machine — install a compiler like g++ and run them locally.

    Q: When should I use getline() instead of >> ?

    Use >> to read one whitespace-separated token at a time (a word or a number) with automatic type conversion. Use getline() when you want a whole line, including the spaces inside it — for example a full name or address. getline() also takes an optional delimiter, so getline(s, field, ',') is the easy way to split CSV data.

    Q: Do I really need to call .close()?

    Not strictly — file streams use RAII, so the destructor closes the file automatically when the stream goes out of scope. But calling .close() explicitly flushes the buffer to disk immediately and frees the file so another part of your program (or another program) can open it. It also makes your intent obvious to the next reader.

    Q: What does ios::binary actually change?

    It turns off text translation. On Windows, text mode rewrites '\n' as '\r\n' on write and back on read; binary mode leaves every byte exactly as-is. You need ios::binary whenever you call .write()/.read() with reinterpret_cast on structs or non-text data, otherwise stray byte translation can corrupt it.

    Q: Why is istringstream useful if it's not a file?

    Because the stream interface is the same. Once you can parse an istringstream you can parse a file — the only difference is where the characters come from. It's also perfect for splitting one line you've already read (with getline) into fields, and for converting text to numbers safely.

    Mini-Challenge: Average a Row of Scores

    No blanks this time — just a brief and an outline. You'll parse a comma-separated line entirely in memory with istringstream, so it runs right here. Build it, run it, and check your output against the example in the comments.

    🎯 Mini-Challenge: average the scores

    Parse the CSV row with istringstream and print the average.

    Try it Yourself »
    C++
    #include <iostream>
    #include <sstream>
    #include <string>
    using namespace std;
    
    int main() {
        // 🎯 MINI-CHALLENGE: average a row of scores
        // The data is a comma-separated line (pretend it came from a CSV file):
        string row = "Maths,72,68,90,85";
        //
        // 1. Wrap "row" in an istringstream.
        // 2. getline(..., ',') the first field into a "subject" string.
        // 3. Loop getline(..., token, ',') over the rest; convert each with stoi(token),
        //    add to a running sum and coun
    ...

    Pro Tips

    • 💡 Prefer the read as your loop test: while (getline(in, line)) beats checking eof() — it never processes a phantom last line.
    • 💡 Read a line, then parse it: getline the whole line from the file, then feed it to an istringstream to split the fields. Clean and robust.
    • 💡 Let RAII help, but flush on purpose: the stream closes itself at scope end, but call .close() when another reader needs the data now.

    🎉 Lesson Complete

    • ofstream writes, ifstream reads, fstream does both — all use << / >>
    • ✅ Always check is_open(); loop on the read so EOF stops you cleanly
    • getline grabs whole lines; >> grabs tokens and converts types
    • ios::app appends, ios::binary writes raw bytes
    • stringstream parses and builds text in memory — same stream skills, no file needed
    • ✅ Close files (or rely on RAII) so the buffer is flushed
    • Next lesson: Exception Safety — keep your resources sound when things go wrong

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy PolicyTerms of Service