views:

56

answers:

2

I'm initially building an index-like mechanism, read each line of the textfile using getline, checking if it matches a known header declaration (string.compare) and saving the tellg position as an index to that point. My intention is then to use seekg(index,ios::beg) to seek to the place in the file where the header is. After reading through the file once when building my index and calling seekg(0,ios::beg) the next getline returns an empty string where I expect to see the first line in the file.

a portion of my code is below to better highlight my issue

//build the index
while (! m_fileIn.eof())
{
   getline (m_fileIn,lineRead);
   int lineID = getLineID(lineRead);
   if(lineID==1)       //if its an STRM 
   {
   //save the index
   }
}

// start reading the file data
m_fileIn.seekg(0,ios::beg);
//read first line (title)

the getLineID function returns an int depending on the result of the string comparison.

is the use of getline incorrect if I need to re-read the file?

+1  A: 

Your problem is caused because you have a Bad bit set inside the stream.
Operations on the stream will be ignored until the Bad bit has been reset.

// After the loop reset the Bad Bits.
m_fileIn.clear()

Note: A Bad bit is one of many error conditions including EOF

But that is not your major problems:

You are using the Classic anti pattern for reading a file:
Rather use this.

while (getline (m_fileIn,lineRead))
{
   int lineID = getLineID(lineRead);
   if(lineID==1)       //if its an STRM 
   {
   //save the index
   }
}

The problem is that the EOF is not set until you read past it.
The last valid read reads UPTO but not past the EOF (therefore EOF is not set).

So consider the situation where you have read the last line in the file. The EOF has not been set as you have not read past it. So the loop is entered. You now execute getline(). This tries to read past EOF as there is absolutely no data to read (not a single byte). So getline() fails now you are calling getlineID() using lineRead whose value is indeterminate (the standard does not say what happens to lineRead when EOF condition is hit; but it probably has the value of last line read as you don't seem to reset it inside the loop).

Another problem with this code is it only checks for EOF. What happens when another type of error occurs? The loop actually gets stuck in an infinite loop; this is because when an error flag is set no more reading happens so you can never reach to the EOF.

while (! m_fileIn.eof())
{
   getline (m_fileIn,lineRead)
   int lineID = getLineID(lineRead);
   if(lineID==1)       //if its an STRM 
   {
   //save the index
   }
}

The solution is to perform the read operation in the while loop test. This works because getline() returns the stream passed as the first parameter. Therefore the stream gets used in a boolean context. When a stream is used in a boolean context it is converted into a type that can be used as a boolean; the value of this object is equivalent true if there are no errors and false otherwise.

In this situation the read is attempted, but if it fails the loop is never entered.

Martin York
A: 

After posting here and trawling various websites I added the line

m_fileIn.clear();

before the line

getline (m_fileIn,lineRead);

by clearing the error flags (i'm assuming eof error) I was able to continue as normal.

Martin - I'd be really interested to find out more on the anti-pattern which I unknowingly used, I've updated my code to include your changes, many thanks.

Dougie
This is the anti-pattern :- `while (! m_fileIn.eof())` Don't use it. This anti-pattern is not C++ specific but a general to all languages (I know). From Perl -> Php -> Python -> C -> Java -> Fortran etc etc. Files are always read in the same way (do the read operation as part of the loop conditional expression).
Martin York