1

Hello dear helpful people

I have run into a problem using the seekg() function of the ifstream class. My goal is to read out an integer from a text file with known layout. Consider the following as example file named Ph_Sn.cfg.

some random text bla bla
48 molecules of all types
much more text
and numbers etc etc

In the actual program I am opening the file and perform multiple tasks that require me to jump around a bit with the readout position. I have tracked my problem and created a minimal working example, which is the code below.
In short: Moving the stream cursor by calling the seekg() function somehow corrupts the stream object and makes the next >> operator set a failbit.

#include <iostream>
#include<fstream>
using std::ifstream;
using std::cin;
using std::cout;
using std::endl;
using std::ios;

int skipline(ifstream&);

int main() {
    char *file_name = "Ph_Sn.cfg";
    ifstream file;
    int input;

    file.open(file_name);
    skipline(file); //skipping a certain amount of lines (here: 1) since I know the file layout
    const ifstream::streampos correctPosition = file.tellg(); //stream position before the integer I want to read
    file>>input;
    cout<<"Integer of interest: "<<input<<endl; //check if integer was read correctly

    file.seekg(ios::beg); //revert to start of the file, just for demonstration in this example
    skipline(file);
    cout<<"good flag, failbit, badbit, eof = "<<file.good()<<" "<<file.fail()<<" "<<file.bad()<<" "<<file.eof()<<endl; //checking flags just for demonstration

    file.seekg(correctPosition); //if this line is commented out, the second reading succeeds
    cout<<"after seekg comparison tellg==correctPosition "<<(file.tellg()==correctPosition)<<endl; //after calling seekg the position is still correct
    cout<<"after seekg: good flag, failbit, badbit, eof = "<<file.good()<<" "<<file.fail()<<" "<<file.bad()<<" "<<file.eof()<<endl; //checking again, still no errors

    file>>input; //attempt to read out the integer again
    cout<<"Integer of interest: "<<input<<endl;
    cout<<"good flag, failbit, badbit, eof = "<<file.good()<<" "<<file.fail()<<" "<<file.bad()<<" "<<file.eof()<<endl; //the >> operator set the fail flag

    cin>>input; //I don't want the console to close to see the output
    return 0;
}

int skipline(ifstream &file)
{
    int code;
    if(!file)
        return(0);
    else
    {
        do
        {
            code=file.get();
        }
        while (code!=10);
    }
    return(1);//no error
}

Compiling the code and running the .exe file in the directory in which my Ph_Sn.cfg lies gives me the following output on the console:

Integer of interest: 48
good flag, failbit, badbit, eof = 1 0 0 0
after seekg comparison tellg==correctPosition 1
after seekg: good flag, failbit, badbit, eof = 1 0 0 0
good flag, failbit, badbit, eof = 0 1 0 0
Integer of interest: 0

As mentioned in the comments of the code, simply commenting out the file.seekg(correctPosition); operation gives the correct integer at the second read.

I tried to find answers to similar problems, but in most cases the eof flag was set and the problem was solved by calling file.clear(). This sadly does not seem to help in my case. I also found this post, but i think my problem is different since (am I horribly wrong?):

  1. Failbit is NOT set right after seekg() but after the >> operator
  2. My file is pretty small (some kb)
  3. I am opening the file in text mode

I wonder if the problem does not lie within the code but rather in my setup of eclipse. I would like to have a conformation if the code works, if compiled independently and if so, what kind of setting could be responsible for this (in my eyes) strange behaviour. I am running a 32 bit Windows OS, eclipse-Luna with cdt addon and the MinGW GCC toolchain.

I appreciate any kind of help or hints. This problem has me occupied for a whole week by now.

Community
  • 1
  • 1
Detlef
  • 11
  • 2
  • If the file has a known layout, why are you opening it in text mode? Wouldn't you want to open it in binary mode, thus you know the exact byte where the data lies? – PaulMcKenzie May 18 '15 at 15:26
  • Plus, attempting to use `seekg` on a file opened in text mode (where cr/lf translations are done) is error prone. – PaulMcKenzie May 18 '15 at 15:31
  • I see that i was not specific enough. In fact in only know in which line the integer can be found and that it is the first token in each line. The amount of charakters between the numbers i want is random and multiple spaces in front of my numbers are possible. Is it still worthwhile to try an implementation via binary mode? – Detlef May 18 '15 at 15:35
  • Why are you doing this using file I/O? Just read the entire string in and parse it in memory using one of the many ways to parse a string in C++. – PaulMcKenzie May 18 '15 at 15:38
  • I encountered this problem while modifying a program someone else wrote. I am not sure why this way of implementation was favored. My guess would be that there is some perfomance gain this way, since this is a program for chemistry related simulations that basically is supposed to run as quickly as possible when reading and writing a lot of stuff in the RAM. I'd like to find a solution that requires as little alteration in the program structure as possible. – Detlef May 18 '15 at 15:44
  • Reading a line of text and parsing it *in memory* is probably just as fast, if not faster, then trying to read the file and use seekg(). But the bottom line is that using seekg() on a file opened in text mode is error prone. You cannot get away from that. Were you not aware of the carriage return / line feed issues with text mode? – PaulMcKenzie May 18 '15 at 15:55
  • I have read that there are issues with text mode and line ending characters. I am kind of sad if there is no solution regarding the actual problem at hand since restructuring the program in a huge way such as changing all io functions will be a lot of work. I'd like to find solution rather than a different approach. – Detlef May 18 '15 at 16:47
  • Then I suggest you open your file in binary mode, and work with that. Then you have to probably forget about using the streaming operators and do straight `read()`'s. As you stated: `In the actual program I am opening the file and perform multiple tasks that require me to jump around a bit with the readout position` That really does require binary mode. You just won't get anywhere tackling all this in text mode. – PaulMcKenzie May 18 '15 at 16:52
  • I will keep an eye on this post to see if there is a more comfortable solution for my problem. Thanks so far for your recommendations, i will probably try to move to binary reading as you suggested if nobody has further ideas. – Detlef May 18 '15 at 18:18

0 Answers0