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++.
Part of the free C++ course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn
💡 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.
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.
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.
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.
One more. This time you'll read numbers with >> and build a report string with ostringstream . Fill in the two blanks:
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
Task
Code
Open file to write
ofstream out("f.txt");
Open file to read
ifstream in("f.txt");
Read & write
fstream io("f.txt");
Append mode
ofstream(f, ios::app)
Binary mode
ifstream(f, ios::binary)
Check it opened
if (in.is_open())
Read a line
getline(in, line)
Read a token
in >> word
Split on a char
getline(ss, f, ',')
Build a string
oss << x; oss.str()
Close the file
stream.close();
Frequently Asked Questions
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.
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
Practice quiz
Which stream type opens a file for WRITING?
- std::ifstream
- std::istringstream
- std::ofstream
- std::cin
Answer: std::ofstream. std::ofstream (output file stream) opens a file for writing; ifstream is for reading.
What should you always do right after opening a file stream?
- Check is_open() before reading or writing
- Call .flush()
- Call .seekg(0)
- Set ios::binary mode
Answer: Check is_open() before reading or writing. A wrong path or read-only folder fails silently, so always guard with is_open() first.
When should you use getline() instead of >> ?
- When you want one whitespace-separated token
- getline() and >> are identical
- Only when reading numbers
- When you want a whole line, including the spaces inside it
Answer: When you want a whole line, including the spaces inside it. >> reads one token (a word or number); getline() grabs a whole line, and with a delimiter it splits CSV fields.
What does the file mode std::ios::app do?
- Opens the file in binary mode
- Appends new writes to the end, keeping existing content
- Truncates the file to empty
- Opens the file for reading only
Answer: Appends new writes to the end, keeping existing content. ios::app appends: writes go to the end and existing content is kept — ideal for log files.
Why is looping on while (!in.eof()) a common bug?
- EOF is set AFTER a failed read, so it processes the last line twice
- eof() does not exist on ifstream
- It is too slow
- It only works in binary mode
Answer: EOF is set AFTER a failed read, so it processes the last line twice. Loop on the read itself — while (getline(in, line)) or while (in >> x) — so EOF stops you cleanly.
What does std::ios::binary change?
- It compresses the file
- It makes the file read-only
- It turns off text translation so bytes are written exactly as-is
- It appends to the file
Answer: It turns off text translation so bytes are written exactly as-is. Binary mode skips newline translation; you need it for .write()/.read() on structs and other non-text data.
How do you read up to the next comma in a CSV field with getline?
- getline(iss, field, comma)
- getline(iss, field, ',')
- iss >> field >> ','
- getline(iss.comma(), field)
Answer: getline(iss, field, ','). getline(stream, target, ',') reads characters up to the next comma delimiter.
How do you get the finished string out of a std::ostringstream named report?
- report.get()
- report.string()
- report >> result
- report.str()
Answer: report.str(). You build text with << then call .str() to pull the result out of the ostringstream.
Why do the 'Your Turn' exercises in this lesson use std::stringstream instead of real files?
- stringstream is faster than files
- Online compilers often have no writable filesystem, but stringstream works entirely in memory
- Files cannot hold text
- stringstream is required by C++20
Answer: Online compilers often have no writable filesystem, but stringstream works entirely in memory. Sandboxed online compilers may lack a writable filesystem, so in-memory stringstream runs anywhere.
Do you strictly need to call .close() on a file stream?
- Yes, or the file is corrupted
- Only for ifstream, never ofstream
- No — RAII closes it at scope end, but .close() flushes immediately and frees the file for others
- Only in binary mode
Answer: No — RAII closes it at scope end, but .close() flushes immediately and frees the file for others. File streams are RAII, so the destructor closes them; calling close() explicitly flushes the buffer and releases the file now.
Continue this course
- Previous: Memory Allocation Internals
- Next: Exception Safety