C++ Reading a file till the end


Example

Reading a text file line-by-line

A proper way to read a text file line-by-line till the end is usually not clear from ifstream documentation. Let's consider some common mistakes done by beginner C++ programmers, and a proper way to read the file.

Lines without whitespace characters

For the sake of simplicity, let's assume that each line in the file contains no whitespace symbols.

ifstream has operator bool(), which returns true when a stream has no errors and is ready to read. Moreover, ifstream::operator >> returns a reference to the stream itself, so we can read and check for EOF (as well as for errors) in one line with very elegant syntax:

std::ifstream ifs("1.txt");
std::string s;
while(ifs >> s) {
    std::cout << s << std::endl;
}

Lines with whitespace characters

ifstream::operator >> reads the stream until any whitespace character occurs, so the above code will print the words from a line on separate lines. To read everything till the end of line, use std::getline instead of ifstream::operator >>. getline returns reference to the thread it worked with, so the same syntax is available:

while(std::getline(ifs, s)) {
    std::cout << s << std::endl;
}

Obviously, std::getline should also be used for reading a single-line file till the end.

Reading a file into a buffer at once

Finally, let's read the file from the beginning till the end without stopping at any character, including whitespaces and newlines. If we know the exact file size or upper bound of the length is acceptable, we can resize the string and then read:

s.resize(100);
std::copy(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(),
    s.begin());

Otherwise, we need to insert each character to the end of the string, so std::back_inserter is what we need:

std::copy(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(),
    std::back_inserter(s));

Alternatively, it is possible to initialize a collection with stream data, using a constructor with iterator range arguments:

std::vector v(std::istreambuf_iterator<char>(ifs),
    std::istreambuf_iterator<char>());

Note that these examples are also applicable if ifs is opened as binary file:

std::ifstream ifs("1.txt", std::ios::binary);

Copying streams

A file may be copied to another file with streams and iterators:

std::ofstream ofs("out.file");
std::copy(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(),
    std::ostream_iterator<char>(ofs));
ofs.close();

or redirected to any other type of stream with a compatible interface. For example Boost.Asio network stream:

boost::asio::ip::tcp::iostream stream;
stream.connect("example.com", "http");
std::copy(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(),
    std::ostream_iterator<char>(stream));
stream.close();

Arrays

As iterators might be thought of as a generalization of pointers, STL containers in the examples above may be replaced with native arrays. Here is how to parse numbers into array:

int arr[100];
std::copy(std::istream_iterator<char>(ifs), std::istream_iterator<char>(), arr);

Beware of buffer overflow, as arrays cannot be resized on-the-fly after they were allocated. For example, if the code above will be fed with a file that contains more than 100 integer numbers, it will attempt to write outside the array and run into undefined behavior.