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++.
Learn Python, JavaScript, Java and more with free interactive lessons, real projects and AI-powered help. Beginner-friendly.
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.
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:
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.
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.