1

This is how I usually read files with std::ifstream:

while (InFile.peek() != EOF)
{
    char Character = InFile.get();
    // Do stuff with Character...
}

This avoids the need of an if statement inside the loop. However, it seems that even peek() causes eofbit to be set, which makes calling clear() necessary if I plan on using that same stream later.

Is there a cleaner way to do this?

Maxpm
  • 24,113
  • 33
  • 111
  • 170
  • @Tony I often forget to call InFile.clear() before doing additional operations later in the program, which causes some hard-to-find bugs. – Maxpm Apr 07 '11 at 14:51
  • @Maxpm: If you're going to re-read the file after EOF, why not just read it into a string, and then copy out into a stringstream and use that for each intermediate operation? – Puppy Apr 07 '11 at 14:56
  • @DeadMG That would be impractical in my case, as I'm making a file-reading class and maintaining a `stringstream` as a private member would be cumbersome. – Maxpm Apr 07 '11 at 15:00
  • @Maxpm: What, the huge inconvenience of about 20 characters to define it, and some small refactoring, to save yourself hours of debugging? – Puppy Apr 07 '11 at 15:02

2 Answers2

2

Typically, you would just use

char x;
while(file >> x) {
    // do something with x
}
// now clear file if you want

If you forget to clear(), then use an RAII scope-based class.

Edit: Given a little more information, I'd just say

class FileReader {
    std::stringstream str;
public:
    FileReader(std::string filename) {
        std::ifstream file(filename);
        file >> str.rdbuf();
    }
    std::stringstream Contents() {
        return str;
    }
};

Now you can just get a copy and not have to clear() the stream every time. Or you could have a self-clearing reference.

template<typename T> class SelfClearingReference {
    T* t;
public:
    SelfClearingReference(T& tref)
        : t(&tref) {}
    ~SelfClearingReference() {
        tref->clear();
    }
    template<typename Operand> T& operator>>(Operand& op) {
        return *t >> op;
    }
};
Puppy
  • 144,682
  • 38
  • 256
  • 465
0

I'm not sure I understand. Infile.peek() only sets eofbit when it returns EOF. And if it returns EOF, and later read is bound to fail; the fact that it sets eofbit is an optimization, more than anything else.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • The idea is that I can use the same stream later on and run through it again (after using `seekg(0, std::ios_base::beg)`), but even then it still needs `clear()` to be called beforehand. – Maxpm Apr 07 '11 at 19:26