Modern examples of file handling in C++: reading and writing files
Before any theory, let’s look at a simple, modern example of file handling in C++: reading and writing files using <fstream> and basic error checks.
#include <fstream>
#include <iostream>
#include <string>
int main() {
// Write to a file
{
std::ofstream out{"example.txt"};
if (!out) {
std::cerr << "Failed to open file for writing\n";
return 1;
}
out << "Hello, C++ file handling!\n";
out << "Line 2" << '\n';
} // out goes out of scope, file is closed automatically
// Read from the same file
{
std::ifstream in{"example.txt"};
if (!in) {
std::cerr << "Failed to open file for reading\n";
return 1;
}
std::string line;
while (std::getline(in, line)) {
std::cout << "Read: " << line << '\n';
}
}
}
This is the baseline pattern you’ll see repeated in many of the best examples of file handling in C++: reading and writing files with RAII, simple checks, and clear scope boundaries.
Text file examples of file handling in C++: line-by-line and whole-file
Most real examples of file handling in C++ start with plain text—logs, configuration, or simple data dumps. There are two common patterns: reading line by line, and reading the whole file into memory.
Reading a configuration file line by line
Imagine a simple app.conf file:
port=8080
debug=true
log_level=info
Here’s an example of file handling in C++ that parses this into a map-like structure:
#include <fstream>
#include <iostream>
#include <string>
#include <unordered_map>
std::unordered_map<std::string, std::string> load_config(const std::string& path) {
std::unordered_map<std::string, std::string> config;
std::ifstream in{path};
if (!in) {
throw std::runtime_error("Could not open config file: " + path);
}
std::string line;
while (std::getline(in, line)) {
if (line.empty() || line[0] == '#') continue; // skip comments
auto pos = line.find('=');
if (pos == std::string::npos) continue; // skip malformed lines
std::string key = line.substr(0, pos);
std::string value = line.substr(pos + 1);
config[key] = value;
}
return config;
}
This is one of those real examples of file handling in C++: reading and writing files where the file format is simple but still needs basic parsing and validation.
Reading an entire text file into a string
Sometimes you just want the whole file as a single string—maybe to pass to a JSON parser or a template engine.
#include <fstream>
#include <sstream>
#include <string>
std::string read_whole_file(const std::string& path) {
std::ifstream in{path};
if (!in) {
throw std::runtime_error("Could not open file: " + path);
}
std::ostringstream buffer;
buffer << in.rdbuf();
return buffer.str();
}
This pattern shows up in many of the best examples of file handling in C++ because it’s short, readable, and works well for moderate-size files.
Writing text: logs, CSVs, and append mode
Text output is where file handling becomes part of application behavior: logging, exporting metrics, or generating reports.
Simple logging to a file
A minimal logger that appends to a log file:
#include <fstream>
#include <iostream>
#include <string>
#include <chrono>
#include <iomanip>
void log_message(const std::string& path, const std::string& message) {
std::ofstream out{path, std::ios::app}; // append mode
if (!out) {
std::cerr << "Failed to open log file: " << path << '\n';
return;
}
using clock = std::chrono::system_clock;
auto now = clock::to_time_t(clock::now());
out << std::put_time(std::localtime(&now), "%Y-%m-%d %H:%M:%S")
<< " - " << message << '\n';
}
This is a very typical example of file handling in C++: reading and writing files where the write pattern is append-only and order matters.
Writing CSV data for analytics
Even in 2025, CSV is still everywhere—from quick exports to data pipelines feeding into tools like R or Python. Here’s a tiny CSV writer:
#include <fstream>
#include <vector>
#include <string>
void write_csv(const std::string& path,
const std::vector<std::vector<std::string>>& rows) {
std::ofstream out{path};
if (!out) {
throw std::runtime_error("Could not open CSV file for writing: " + path);
}
for (const auto& row : rows) {
bool first = true;
for (const auto& cell : row) {
if (!first) out << ',';
// very naive escaping; real code should handle quotes properly
out << '"' << cell << '"';
first = false;
}
out << '\n';
}
}
Many real examples of file handling in C++: reading and writing files for data science workflows look a lot like this—plain CSV with simple quoting.
Binary examples of file handling in C++: reading and writing structs
Text is nice for humans, but binary I/O still matters for performance-sensitive work, networking, and game engines.
Writing and reading a simple struct
Here’s a small, self-contained example of binary file handling in C++:
#include <fstream>
#include <iostream>
#pragma pack(push, 1)
struct Record {
int id;
double value;
};
#pragma pack(pop)
void write_record(const std::string& path, const Record& rec) {
std::ofstream out{path, std::ios::binary};
if (!out) throw std::runtime_error("Could not open file for writing");
out.write(reinterpret_cast<const char*>(&rec), sizeof(rec));
}
Record read_record(const std::string& path) {
std::ifstream in{path, std::ios::binary};
if (!in) throw std::runtime_error("Could not open file for reading");
Record rec{};
in.read(reinterpret_cast<char*>(&rec), sizeof(rec));
if (!in) throw std::runtime_error("Failed to read full record");
return rec;
}
This is one of the classic examples of file handling in C++: reading and writing files with raw structs. In real systems, you’d also think about endianness, alignment, and versioning, or lean on a format like Protocol Buffers or FlatBuffers.
Binary I/O for large arrays
When you’re dealing with numeric arrays—think image buffers or simulation data—you often want to read and write in big chunks:
#include <vector>
void write_doubles(const std::string& path, const std::vector<double>& data) {
std::ofstream out{path, std::ios::binary};
if (!out) throw std::runtime_error("Could not open file for writing");
out.write(reinterpret_cast<const char*>(data.data()),
static_cast<std::streamsize>(data.size() * sizeof(double)));
}
std::vector<double> read_doubles(const std::string& path) {
std::ifstream in{path, std::ios::binary};
if (!in) throw std::runtime_error("Could not open file for reading");
in.seekg(0, std::ios::end);
std::streamsize size = in.tellg();
in.seekg(0, std::ios::beg);
std::vector<double> data(size / sizeof(double));
in.read(reinterpret_cast<char*>(data.data()), size);
if (!in) throw std::runtime_error("Failed to read all data");
return data;
}
This pattern shows up in high-performance computing and simulation code, and it’s a good example of file handling in C++: reading and writing files with manual buffer management.
Safer file handling with std::filesystem (C++17 and later)
Modern C++ gives you a better way to reason about paths and existence checks via std::filesystem. In 2024–2025, there’s no reason to avoid it if your toolchain is even remotely up to date.
Checking if a file exists before reading
#include <filesystem>
#include <fstream>
#include <iostream>
void print_file_if_exists(const std::filesystem::path& path) {
namespace fs = std::filesystem;
if (!fs::exists(path)) {
std::cerr << "File does not exist: " << path << '\n';
return;
}
std::ifstream in{path};
if (!in) {
std::cerr << "Failed to open file: " << path << '\n';
return;
}
std::cout << in.rdbuf();
}
This is one of the cleaner examples of file handling in C++: reading and writing files while also being honest about the filesystem. You check existence, you open, you stream.
Writing to a temp file, then renaming (atomic-ish updates)
When you’re updating config or state files, you don’t want half-written files if the program crashes. A common pattern is: write to a temp file, then rename.
#include <filesystem>
#include <fstream>
void atomic_write(const std::filesystem::path& path, const std::string& content) {
namespace fs = std::filesystem;
fs::path tmp = path;
tmp += ".tmp";
{
std::ofstream out{tmp, std::ios::trunc};
if (!out) throw std::runtime_error("Could not open temp file for writing");
out << content;
if (!out) throw std::runtime_error("Failed to write full content");
}
fs::rename(tmp, path); // on many systems this is atomic
}
If you’re looking for best examples of file handling in C++: reading and writing files that won’t corrupt user data, this pattern deserves a spot on your short list.
Parsing structured text: JSON-like configs and simple line formats
You’ll often see examples of file handling in C++: reading and writing files that look like JSON, YAML, or some ad-hoc format. In real projects, you’d probably use a library like nlohmann/json, but here’s a simple idea using line-based key-value pairs.
A minimal save/load for settings
#include <fstream>
#include <string>
#include <unordered_map>
void save_settings(const std::string& path,
const std::unordered_map<std::string, std::string>& settings) {
std::ofstream out{path};
if (!out) throw std::runtime_error("Could not open settings file for writing");
for (const auto& [key, value] : settings) {
out << key << '=' << value << '\n';
}
}
std::unordered_map<std::string, std::string>
load_settings(const std::string& path) {
return load_config(path); // reuse earlier example
}
This isn’t fancy, but it’s realistic. Many production systems still use simple line-based formats for settings because they’re easy to inspect, edit, and version-control.
Trends in C++ file handling for 2024–2025
If you skim modern C++ codebases and teaching material from places like cppreference.com or university courses hosted on .edu domains, a few patterns stand out:
std::filesystemis now standard practice for paths and existence checks.- RAII-based streams (
std::ifstream,std::ofstream,std::fstream) remain the default choice. - Asynchronous I/O and memory-mapped files are increasingly handled by libraries or platform APIs, not hand-rolled code.
- For structured data, developers lean more on established formats and libraries (JSON, Protocol Buffers) rather than inventing new binary layouts.
The examples of file handling in C++: reading and writing files in this article reflect that shift: small, composable functions that do one thing cleanly instead of giant monolithic I/O routines.
If you want to explore more about how systems handle data, sites like NIST and data.gov publish open datasets and technical guidance that often end up being processed by C++ and other languages in data pipelines.
Putting it together: a tiny log analyzer
To close, here’s a slightly more realistic example of file handling in C++ that combines reading and writing files: a simple log analyzer that reads a log file, filters lines, and writes a summary.
#include <fstream>
#include <iostream>
#include <string>
void summarize_errors(const std::string& input_path,
const std::string& output_path) {
std::ifstream in{input_path};
if (!in) {
throw std::runtime_error("Could not open input log: " + input_path);
}
std::ofstream out{output_path};
if (!out) {
throw std::runtime_error("Could not open output file: " + output_path);
}
std::string line;
std::size_t error_count = 0;
while (std::getline(in, line)) {
if (line.find("ERROR") != std::string::npos) {
++error_count;
out << line << '\n'; // write only error lines
}
}
out << "Total ERROR lines: " << error_count << '\n';
}
This function is a good summary of many best examples of file handling in C++: reading and writing files in one pass, with clear responsibilities and minimal surprise.
FAQ: examples of file handling in C++
Q: What are some simple examples of file handling in C++: reading and writing files?
Some of the simplest examples include: reading a text file line by line with std::getline, writing logs by appending to a file with std::ofstream, reading an entire file into a std::string using rdbuf(), and writing binary structs with std::ios::binary. The code samples above show each pattern in context.
Q: Can you show an example of safe file writing that avoids partial data?
The atomic_write function using a temporary file and std::filesystem::rename is a good example of safer writing. You write everything to a temp file, close it, then rename it over the original. If the program crashes during the write, the original file is still intact.
Q: When should I use binary vs text in C++ file handling?
Use text when you care about readability, debugging, and interoperability with tools like spreadsheets or scripting languages. Use binary when performance and exact representation matter, such as large numeric arrays, images, or custom binary protocols. Many real examples of file handling in C++: reading and writing files mix both—binary for heavy data, text for metadata.
Q: Do I still need to call close() on C++ file streams?
Not usually. In modern C++, streams close automatically when they go out of scope. Most of the best examples of file handling in C++ rely on this RAII behavior instead of explicit close() calls, except in rare cases where you want to close early and reuse the same variable.
Q: How do I handle large files efficiently in C++?
For large files, avoid reading everything into memory at once. Process them in chunks or line by line, as shown in the log analyzer example. For performance-critical code, you might look into memory-mapped I/O or asynchronous APIs, but those go beyond basic examples of file handling in C++: reading and writing files with <fstream>.
Related Topics
Practical examples of polymorphism in C++: function overloading
Best examples of dynamic memory allocation in C++: new and delete
Practical examples of C# variable declaration and initialization examples
Modern examples of C++ operator overloading: custom operators examples that actually matter
Best examples of C# conditional statements: examples & explanations
Real‑world examples of C# exception handling: 3 practical patterns every developer should know
Explore More C++ Code Snippets
Discover more examples and insights in this category.
View All C++ Code Snippets