I have a function (legacy) that reads the first few lines of a file to determine its type, then closes and reopens the file so it can re-read the entire file using the correct interpreter. The gist is:
void readFile(const char *filename) {
ifstream is(filename);
Filetype ft = determineFileType(is);
is.close();
is.open(filename);
parseFile(is, ft);
}
I needed a similar function that can work on an already-opened stream. I created a new function that takes an ostream & instead of a char *filename — basically this:
void readFile(istream &is) {
std::ios::streampos pos = is.tellg();
Filetype ft = determineFileType(is);
is.seekg(pos);
parseFile(is, ft);
}
It seems to work when the istream is actually a stringstream or an fstream but I wonder if I’m just getting lucky. I also did a small test on seekg-ing std::cin and it worked, which surprised me.
So my question: what kinds of streams are you allowed to use seekg on? When will it fail? Spec references would be great — I looked through and the stuff on seekg, pubseekpos, seekpos, seekoff weren’t helpful at all.
I’d like to reimplement the original function in terms of the new (as below), but I just don’t know if that’s safe.
void readFile(const char *filename) {
ifstream is(filename);
readFile(is);
is.close();
}
The only real answer one can give is that it works where it works. In
the case of
std::stringbuf, it should work everywhere. In the case ofstd::filebuf, whether it works or not depends on the system; it willgenerally work if the
filebufis opened on an actual file, but willusually fail (perhaps silently, if the system doesn’t report an error)
for many other types of input: from a keyboard, or a named pipe, for
example.
A more robust solution would be to cache the initial input, and re-read it from the cache.