Skip to content

/commands/cpp/read-file-line-by-line

c++ read a file line by line with std::getline and ifstream

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash)updated
tool
C++
versions
C++98+, std::filesystem: C++17
os
any

To read a text file line by line in C++, open it with std::ifstream file("data.txt"), check that it opened, and loop with while (std::getline(file, line)). Each iteration gets one line without the \n; the loop ends at the end of the file or on a read error. The file is closed automatically when file goes out of scope.

Read lines, skip blanks, count

The example uses Clang 20 from the ziglang package on PyPI (with libc++), run through uv; cxx stands for it. On your machine, write g++ or clang++:

bash
cxx() { uv run -q --no-project --python 3.13 --with ziglang==0.15.1 python -m ziglang c++ -fno-color-diagnostics "$@"; }
printf 'alpha\r\nbeta\n\ngamma' > data.txt
cat > lines.cpp <<'EOF'
#include <fstream>
#include <iostream>
#include <string>

int main() {
    std::ifstream file("data.txt", std::ios::binary);   // binary: see the \r on every platform
    if (!file) {
        std::cerr << "cannot open data.txt\n";
        return 1;
    }
    std::string line;
    int n = 0, blank = 0;
    while (std::getline(file, line)) {
        bool cr = !line.empty() && line.back() == '\r';
        if (cr) line.pop_back();                          // strip a Windows line ending
        if (line.empty()) { ++blank; continue; }
        std::cout << ++n << ": [" << line << "]" << (cr ? " (had \\r)" : "") << '\n';
    }
    std::cout << n << " lines, " << blank << " blank\n";

    std::ifstream missing("missing.txt");
    std::cout << "missing.txt open: " << std::boolalpha << missing.is_open() << '\n';
}
EOF
cxx -std=c++17 -Wall -Wextra lines.cpp -o lines && ./lines

Output

1: [alpha] (had \r)
2: [beta]
3: [gamma]
3 lines, 1 blank
missing.txt open: false

std::getline removes the \n but not a \r, so lines from a file with Windows line endings end in \r unless the stream translates them (text mode on Windows does). The last line is returned even without a final newline. Opening a missing file does not throw; the stream simply tests false.

Variants

CodeWhat it does
while (std::getline(file, line))One line per iteration, without the newline
std::getline(file, field, ',')Read up to another delimiter, for example one CSV field
while (file >> word)Read whitespace-separated words instead of lines
std::getline(std::cin, line)Read standard input line by line
file.exceptions(std::ios::badbit)Throw on real I/O errors instead of silently stopping
std::filesystem::exists(path)Check the path before opening (C++17, <filesystem>)

Pitfalls

  • Not checking the open. if (!file) after construction catches a missing file or missing permissions; without it the loop simply never runs and the program looks like it read an empty file.
  • while (!file.eof()). The classic bug: the last line is processed twice or an empty line is processed at the end. Use the getline call as the condition.
  • Mixing >> and getline. After std::cin >> n, the newline stays in the stream and the next getline returns an empty line; call std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n') in between.
  • Relative paths are resolved against the working directory of the process, which in an IDE is often the build folder.
  • Splitting or converting each line: see split a string by delimiter and convert a string to int.

Confirm it worked

Print the line count and compare it with your editor's line count; printing each line between brackets, as above, makes trailing spaces and \r characters visible.

FAQ

Does std::getline keep the newline?

No. It reads up to the delimiter (\n by default), removes it from the stream and does not store it. A \r from a Windows file opened on Linux does stay at the end of the line.

Why does my loop read the last line twice?

Because it tests eof() before reading: while (!file.eof()) { getline(file, line); ... }. Use the getline call itself as the loop condition, while (std::getline(file, line)), which stops as soon as a read fails.

How do I read the whole file into one string?

std::string text((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()); or read it with a std::stringstream: ss << file.rdbuf().

Sources