C++ File I/O: Reading and Writing Files
C++ provides the <fstream> library for file input and output. It offers three stream classes — ifstream for reading, ofstream for writing, and fstream for both reading and writing. These classes inherit from istream and ostream, so they work with the same operators and functions as cin and cout.
Basic File Operations
Opening a File
#include <fstream>
#include <iostream>
std::ifstream input("data.txt"); // Open for reading
std::ofstream output("output.txt"); // Open for writing
std::fstream io("config.txt"); // Open for both
// Or use open() on a default-constructed stream
std::ifstream file;
file.open("data.txt");Always check if the file opened successfully:
if (!file) {
std::cerr << "Failed to open file\n";
return 1;
---
// Alternative:
if (!file.is_open()) {
std::cerr << "File not found\n";
return 1;
---Reading Text Files
Read line by line:
std::ifstream file("input.txt");
std::string line;
while (std::getline(file, line)) {
std::cout << line << "\n";
---Read word by word:
std::string word;
while (file >> word) {
std::cout << word << "\n";
---Read the entire file at once:
std::ifstream file("input.txt");
std::string content(
std::istreambuf_iterator<char>(file),
std::istreambuf_iterator<char>()
);Writing Text Files
std::ofstream file("output.txt");
file << "Hello, World!\n";
file << "Value: " << 42 << "\n";
file.close();Appending to a File
std::ofstream file("log.txt", std::ios::app);
file << "Log entry\n";File Open Modes
| Mode | Flag | Description |
|---|---|---|
| Read | std::ios::in | Open for reading (default for ifstream) |
| Write | std::ios::out | Open for writing (default for ofstream) |
| Append | std::ios::app | Always write at end of file |
| Binary | std::ios::binary | Open in binary mode |
| Truncate | std::ios::trunc | Truncate file on open (default for ofstream) |
| At end | std::ios::ate | Seek to end immediately after open |
Combine modes with the bitwise OR operator:
std::fstream file("data.bin", std::ios::in | std::ios::out | std::ios::binary);Binary I/O
Reading and writing binary data uses read() and write():
#include <fstream>
struct Record {
int id;
char name[32];
double value;
---;
// Write binary data
Record record{1, "Example", 3.14};
std::ofstream out("records.bin", std::ios::binary);
out.write(reinterpret_cast<const char*>(&record), sizeof(record));
out.close();
// Read binary data
Record loaded;
std::ifstream in("records.bin", std::ios::binary);
in.read(reinterpret_cast<char*>(&loaded), sizeof(loaded));Binary vs Text Mode
On Unix-like systems, binary and text modes are identical. On Windows, text mode translates \n to \r\n on write and \r\n to \n on read. Always use binary mode for non-text data to avoid corruption.
Random Access
Seek to a specific position in a file:
std::ifstream file("data.bin", std::ios::binary);
// Seek to position 100 from beginning
file.seekg(100, std::ios::beg);
// Seek 20 bytes forward from current position
file.seekg(20, std::ios::cur);
// Seek 50 bytes before end
file.seekg(-50, std::ios::end);seekg() for input streams, seekp() for output streams. tellg() and tellp() return the current position:
auto pos = file.tellg();
std::cout << "Current position: " << pos << "\n";Error Handling
File streams maintain error state flags:
| Flag | Meaning | |
fstream versus C-style FILE Operations
C++ provides fstream classes that wrap C’s FILE operations with type safety and RAII:
#include <fstream>
#include <string>
// Writing
std::ofstream out("data.txt");
if (out.is_open()) {
out << "Hello, " << 42 << std::endl;
out.close(); // Optional — destructor closes automatically
---
// Reading
std::ifstream in("data.txt");
std::string word;
int number;
in >> word >> number;The RAII nature of fstream is a major advantage — the file is automatically closed when the fstream object goes out of scope, even if an exception is thrown. This eliminates a common source of resource leaks in C programs.
Binary vs Text Mode
Like C, C++ distinguishes between text and binary modes. Open with std::ios::binary for binary data:
std::ifstream in("data.bin", std::ios::binary);
std::ofstream out("output.bin", std::ios::binary);
// Read binary data
char buffer[256];
in.read(buffer, sizeof(buffer));
auto bytes_read = in.gcount();
// Write binary data
out.write(buffer, bytes_read);Random Access with seekg and seekp
Random access works similarly to C’s fseek, using seekg() for input and seekp() for output:
std::ifstream file("records.dat", std::ios::binary);
file.seekg(100, std::ios::beg); // Go to byte 100 from start
file.read(buffer, sizeof(Record));
file.seekg(-50, std::ios::end); // Go to 50 bytes before end
file.read(buffer, sizeof(Record));
auto pos = file.tellg(); // Current position
For serialization, consider using boost::serialization, Protocol Buffers, or FlatBuffers for cross-platform binary format compatibility.
Error State Flags
fstream objects maintain internal state flags: good(), eof(), fail(), and bad(). The bad() flag indicates an unrecoverable error (disk failure). The fail() flag indicates a recoverable error (format mismatch) or EOF. Always check these flags after I/O operations, or enable exceptions via exceptions():
std::ifstream file("config.txt");
file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
std::string line;
while (std::getline(file, line)) {
process(line);
}
--- catch (const std::ifstream::failure &e) {
std::cerr << "File error: " << e.what() << std::endl;
---FAQ
What is the difference between malloc and new in C++? malloc allocates raw memory without calling constructors; new allocates memory and calls the constructor. In C++, prefer new for objects. free vs delete follows the same pattern — delete calls the destructor.
How do I prevent memory leaks in C/C++? Use RAII (Resource Acquisition Is Initialization) in C++ — smart pointers like std::unique_ptr and std::shared_ptr automatically free memory. In C, always pair every malloc with a free and use tools like Valgrind or AddressSanitizer to detect leaks.
What is undefined behavior in C/C++? Undefined behavior occurs when code performs operations that the language standard does not define — dereferencing a null pointer, buffer overflow, signed integer overflow. The compiler may generate any code, including unexpected results or crashes.
Should I learn C or C++ first? Learn C first if you want to understand low-level memory and system programming. Learn C++ first if you want object-oriented features and the STL. Both are valuable; C++ builds on C concepts.
What is the difference between a header file and a source file? Header files (.h) declare interfaces — function prototypes, class definitions, macros. Source files (.c or .cpp) implement the declarations. Headers are #included; source files are compiled separately and linked.
fstream versus C-style FILE Operations
C++ provides fstream classes that wrap C’s FILE operations with type safety and RAII:
#include <fstream>
#include <string>
// Writing
std::ofstream out("data.txt");
if (out.is_open()) {
out << "Hello, " << 42 << std::endl;
out.close(); // Optional — destructor closes automatically
---
// Reading
std::ifstream in("data.txt");
std::string word;
int number;
in >> word >> number;The RAII nature of fstream is a major advantage — the file is automatically closed when the fstream object goes out of scope, even if an exception is thrown. This eliminates a common source of resource leaks in C programs.
Binary vs Text Mode
Like C, C++ distinguishes between text and binary modes. Open with std::ios::binary for binary data:
std::ifstream in("data.bin", std::ios::binary);
std::ofstream out("output.bin", std::ios::binary);
// Read binary data
char buffer[256];
in.read(buffer, sizeof(buffer));
auto bytes_read = in.gcount();
// Write binary data
out.write(buffer, bytes_read);Random Access with seekg and seekp
Random access works similarly to C’s fseek, using seekg() for input and seekp() for output:
std::ifstream file("records.dat", std::ios::binary);
file.seekg(100, std::ios::beg); // Go to byte 100 from start
file.read(buffer, sizeof(Record));
file.seekg(-50, std::ios::end); // Go to 50 bytes before end
file.read(buffer, sizeof(Record));
auto pos = file.tellg(); // Current position
For serialization, consider using boost::serialization, Protocol Buffers, or FlatBuffers for cross-platform binary format compatibility.
Error State Flags
fstream objects maintain internal state flags: good(), eof(), fail(), and bad(). The bad() flag indicates an unrecoverable error (disk failure). The fail() flag indicates a recoverable error (format mismatch) or EOF. Always check these flags after I/O operations, or enable exceptions via exceptions():
std::ifstream file("config.txt");
file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
std::string line;
while (std::getline(file, line)) {
process(line);
}
--- catch (const std::ifstream::failure &e) {
std::cerr << "File error: " << e.what() << std::endl;
---——|———|
| goodbit | No errors |
| eofbit | End of file reached |
| failbit | Logical error (wrong type, file not found) |
| badbit | Read/write error (disk failure) |
Clear and check error state:
std::ifstream file("data.txt");
if (!file) {
std::cerr << "Cannot open file\n";
return 1;
---
int value;
file >> value;
if (file.fail()) {
std::cerr << "Failed to read integer\n";
file.clear(); // Clear error state
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
---String Streams
String streams (<sstream>) allow I/O operations on strings, useful for parsing and formatting:
#include <sstream>
std::string data = "42 3.14 hello";
std::istringstream iss(data);
int i;
double d;
std::string s;
iss >> i >> d >> s;
// Build strings
std::ostringstream oss;
oss << "Value: " << i << ", " << d;
std::string result = oss.str();Performance Tips
Buffer Size
Increase buffer size for large sequential reads:
constexpr size_t BUFFER_SIZE = 1 << 20; // 1 MB
char buffer[BUFFER_SIZE];
file.rdbuf()->pubsetbuf(buffer, BUFFER_SIZE);Avoid Repeated Open/Close
Opening a file is expensive. Keep the file open while performing multiple operations.
Memory-Mapped Files
For extremely large files, memory mapping can outperform streaming I/O:
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
int fd = open("large.bin", O_RDONLY);
size_t length = lseek(fd, 0, SEEK_END);
void* mapped = mmap(nullptr, length, PROT_READ, MAP_PRIVATE, fd, 0);
// Use mapped as a byte array
munmap(mapped, length);
close(fd);RAII and Resource Management
File streams close automatically when they go out of scope. Use RAII to ensure files are always closed:
void process_file(const std::string& path) {
std::ifstream file(path);
if (!file) {
throw std::runtime_error("Cannot open " + path);
}
// File closes automatically when function exits
// even if an exception is thrown
---File I/O is inherently slower than in-memory operations. Minimize the number of I/O calls by reading larger chunks and processing them in memory. Use buffered operations and avoid seeking back and forth between reads and writes.
For a comprehensive overview, read our article on C File Io Guide.
For a comprehensive overview, read our article on C Memory Management.