Skip to content
Home
C++ File I/O: Reading and Writing Files

C++ File I/O: Reading and Writing Files

C/C++ C/C++ 8 min read 1553 words Beginner ExcellentWiki Editorial Team

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

ModeFlagDescription
Readstd::ios::inOpen for reading (default for ifstream)
Writestd::ios::outOpen for writing (default for ofstream)
Appendstd::ios::appAlways write at end of file
Binarystd::ios::binaryOpen in binary mode
Truncatestd::ios::truncTruncate file on open (default for ofstream)
At endstd::ios::ateSeek 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.

Section: C/C++ 1553 words 8 min read Beginner 756 articles in section Report inaccuracy Back to top