C++ PROGRAMMING ยท 15 MIN STUDY

File input and output

Read and write text files with ifstream and ofstream, and check file operations for failure.

Learning objectives

  • Open a file for reading and writing.
  • Use std::ifstream and std::ofstream.
  • Check whether a file opened successfully.
  • Explain why streams should be checked and closed safely.

Prerequisites: understand variables, functions, strings, and console input/output. Review Variables, Functions, Strings, and Console input/output first. Examples use C++17.

Why files?

Console input disappears when a program ends unless the user saves it elsewhere. A file lets a program store information for a later run, such as settings, reports, or records.

Write a text file

C++17
#include <fstream>
#include <iostream>

int main() {
    std::ofstream output{"notes.txt"};
    if (!output) {
        std::cerr << "Could not open notes.txt\n";
        return 1;
    }
    output << "C++ practice\n";
    output << "Review vectors tomorrow\n";
}

std::ofstream opens a file for output. By default, opening an output file this way truncates an existing file. If the file cannot be opened, the stream enters a failure state. Check the stream before writing.

Read a text file line by line

C++17
#include <fstream>
#include <iostream>
#include <string>

int main() {
    std::ifstream input{"notes.txt"};
    if (!input) {
        std::cerr << "Could not open notes.txt\n";
        return 1;
    }
    std::string line;
    while (std::getline(input, line)) {
        std::cout << line << '\n';
    }
}

std::ifstream opens a file for input. The loop continues while getline successfully reads a line. This is a common and reliable pattern for line-based text files.

Append instead of replace

To add content to an existing file rather than replace its previous contents, use the append mode:

std::ofstream log{"activity.txt", std::ios::app};

Always choose file mode deliberately. Output mode without append normally truncates an existing file; append mode writes at the end.

Resource management

File streams close their file when the stream object is destroyed. This is an example of RAII (Resource Acquisition Is Initialization): the object's lifetime manages the resource lifetime. You can call close() explicitly when you need to check the result of closing or finish the file before the stream object leaves scope, but ordinary code should rely on automatic cleanup.

Common mistakes

  • Assuming a file opened successfully without checking stream state.
  • Using a relative path without knowing the program's working directory.
  • Accidentally truncating an existing file when append mode was intended.
  • Using while (!input.eof()) as the read loop. Check the read operation itself with while (getline(input, line)).
  • Expecting a file to be created in the same directory as the source code; the working directory determines relative paths.

Practice

  1. Write three lines to a file and read them back.
  2. Change the output stream to append mode and confirm that old content remains.
  3. Try opening a file that does not exist for input and show a clear error.
  4. Write a program that counts the number of lines in a text file.

Check your understanding

Why is while(getline(input, line)) preferred to while(!input.eof())?

Answer: It processes a line only when the read succeeds. EOF is usually detected during an attempted read, so checking it before reading can cause an extra failed iteration.

Practice solutions

Show worked solutions
  1. Open an std::ofstream, check it, write each line followed by '\n', let it close, then open an std::ifstream and print each line with a while (std::getline(input, line)) loop.
  2. Open the output stream with std::ios::app, for example std::ofstream output{"notes.txt", std::ios::app};. Check the stream before writing; append mode preserves existing content.
  3. Check if (!input) immediately after constructing the input stream. Print a diagnostic to std::cerr and return a non-zero status if opening failed.
  4. After checking the input stream, initialize std::size_t line_count = 0; and increment it inside while (std::getline(input, line)). Print the count after the loop.

Summary

Use file streams for persistent text data, check stream state after opening, choose truncation or append mode intentionally, and let RAII close the file when the stream leaves scope.

References