loveofprogramming
loveofprogramming

Reputation: 95

Program to read from file line by line

I've been trying to write a code to read from a file line by line:

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
    ifstream jin("Story.txt");
    // ins.open("Story.txt", ios::in);
    if (!jin)
    {
        cout << "File not opened" << endl;
        return 1;
    }
    else{
    char a[100];
    do
    {
        jin.getline(a, 100);
        cout << a << endl;
    } 
    while (!jin.eof());
    jin.close();
    return 0;
    }
}

However, on executing this program on Visual Studio Code on Windows, it behaves as infinite loop. Can someone tell what's wrong?

(I am sure that the file Story.txt exists, no doubt about that)

Upvotes: 1

Views: 117

Answers (2)

Ted Lyngmo
Ted Lyngmo

Reputation: 117168

When std::istream::getline has read 100-1 characters (without finding a newline,\n), it will set the failbit on the stream. This prevents further reading on the stream (unless you reset that state). It does however not set eofbit so you are now in a bit of a pickle. The failbit prevents further reading, and eof() returns false, because eofbit is not set - it will therefore loop indefinitely.

If at least one of the lines in Story.txt is longer than 99 chars, the above is what will happen.

The easiest way out is to use a std::string and std::getline instead:

#include <cerrno>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>

int main() {
    std::ifstream jin("Story.txt");
    if(!jin) {
        std::cerr << "File not opened: " << std::strerror(errno) << std::endl;
        return 1;
    }

    std::string a;
    while(std::getline(jin, a)) {
        std::cout << a << '\n';
    }
    return 0;
}

If you really do not want to use std::getline and std::string, you can, but it's much harder:

#include <cerrno>
#include <cstring>
#include <fstream>
#include <iostream>

int main() {
    std::ifstream jin("Story.txt");
    if(!jin) {
        std::cerr << "File not opened: " << std::strerror(errno) << std::endl;
        return 1;
    }
 
    char a[100];
    while(true) {
        jin.getline(a, 100);
        std::cout << a; // output what we got

        if(jin) {
            // got a complete line, add a newline to the output
            std::cout << '\n';
        } else {
            // did not get a newline
            if(jin.eof()) break; // oh, the end of the file, break out

            // reset the failbit to continue reading the long line
            jin.clear();
        }
    }
}

Upvotes: 1

Lasersk&#246;ld
Lasersk&#246;ld

Reputation: 2225

jin.eof() will only return true if a eof-token is found, and this will not happend unless the file is open. That is what causing your infinite loop.

Then you would probably want something like this:

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
    ifstream jin{"Story.txt"};
    if (!jin)
    {
        cout << "File not opened" << endl;
        return 1;
    }
    for (std::string a; std::getline(jin, a);) { // Read every line
       cout << a << "\n";
    }
    // jin is closed when going out of scope so no need for close();
    return 0;
}

Upvotes: 1

Related Questions