C++ Basic Help

Gamingphreek

Lifer
Mar 31, 2003
11,679
0
81
Ok guys, I can't for the life of me figure out why this stupidly simple piece of C++ code isn't working.

Code:
ifstream txtInFile;

for( theDay = 1; theDay <= 31; theDay++ )
			{
				stringstream txtInFileName( stringstream::in|stringstream::out );
				cout << theDay << endl;
				txtInFileName << "C:\\Documents and Settings\\KMBOYD\\Desktop\\Test\\";
				txtInFileName << "d1_" << theYear;

				if ( theMonth < 10 )
					txtInFileName << "0";
				
				txtInFileName << theMonth;

				if ( theDay < 10 )
					txtInFileName << "0";
					
				txtInFileName << theDay;

				txtInFileName << ".txt";

				cout << "The fileName is " << txtInFileName.str() << endl;
				txtInFile.open( txtInFileName.str().c_str(), ifstream::in|ifstream::beg );
				if ( txtInFile.is_open() )
				{
					cout << "I'm open..." << endl;
				}

				if ( !txtInFile )
                                {
					cout << "Just kidding..." << endl;
                                        continue;
                                }

				int lineNumber = 0;
				while( getline( txtInFile, fileBuffer[lineNumber] ) )
				{
					if ( !strcmp( (fileBuffer[lineNumber].substr( 0, fileBuffer[lineNumber].find(' ')).c_str() ), "SDS" ) )
					{
						continue;
					}

					if ( fileBuffer[lineNumber].empty() )
					{
						continue;
					}

					lineNumber++;
				}

				txtInFile.close();
//Do stuff
}

The first file that it opens, it does so successfully. However, when attempting to open the second file, it outputs both "I'm open..." and "Just kidding". The getline() returns something that causes the entire while loop to test false and continue the entire loop.

Any ideas??

-Kevin

Edit: For further information -- If I start on the second file, that file opens and then the one immediately following that does not. It's like I'm allowed 1 open and close per program -_-
 
Last edited:

sao123

Lifer
May 27, 2002
12,653
205
106
you used !txtInFile, IIRC should not that be !txtInFile.fail() ??

please post the entire program, and ill be happy to assist in debugging.
 

Gamingphreek

Lifer
Mar 31, 2003
11,679
0
81
Well my coworker actually just managed to fix it - though we are not entirely sure why it works.

If I had a txtInFile.clear() immediately above the txtInFile.open(...), the programs runs like a charm. Any ideas why? Could the .close() be setting a failbit to prevent against reusing file descriptors?

Thanks,
-Kevin
 

brandonb

Diamond Member
Oct 17, 2006
3,731
2
0
The file class may be keeping a position of where the current stream location is? Maybe clear is resetting that. Is there a command to reset the stream position to the front of the buffer?

ifstream::in|ifstream::beg is there and I assume that is supposed to reset the positiong, are you using the | correctly? Is it giving you the value that you desire? I'd check there if I was going to debug this.

(Sorry I haven't done C++ in a few years, so this is somewhat a shot in the dark)
 
Last edited:

sao123

Lifer
May 27, 2002
12,653
205
106
I suspect the continue is exiting too far out of the loop structure, and on failure the txtInFile.close is being skipped, which could be causing the next iteration to fail.


im doing some stripe work, so ill post that in a bit.
 

Schmide

Diamond Member
Mar 7, 2002
5,712
978
126
Code:
if ( txtInFile.is_open() )
{
	cout << "I'm open..." << endl;
}

if ( !txtInFile )
{
	cout << "Just kidding..." << endl;
	continue;
}

This is the problem. txtInFile will always be nonzero as it is a class not a pointer. Just change this to an else just kidding continue.

Code:
if ( txtInFile.is_open() )
{
	cout << "I'm open..." << endl;
} else {
	cout << "Just kidding..." << endl;
	continue;
}
                    }
 

sao123

Lifer
May 27, 2002
12,653
205
106
Code:
if ( txtInFile.is_open() )
{
    cout << "I'm open..." << endl;
}
 
if ( !txtInFile )
{
    cout << "Just kidding..." << endl;
    continue;
}

This is the problem. txtInFile will always be nonzero as it is a class not a pointer. Just change this to an else just kidding continue.

Code:
if ( txtInFile.is_open() )
{
    cout << "I'm open..." << endl;
} else {
    cout << "Just kidding..." << endl;
    continue;
}
                    }



i did this already, but a failure, still causes the immediate next success to fail also...
ill post some striped conde soon.
 

Venix

Golden Member
Aug 22, 2002
1,084
3
81
"if (!txtInFile)" is perfectly valid. istream has an operator! implementation that checks failbit. If it didn't implement operator!, that line would just result in a compile time error.

Your problem is that getline() will set failbit if it doesn't read any data (e.g. last line of the file is empty). close() and open() do not reset failbit, so it will still be set when you attempt to open another file. As far as I know, this was just an oversight by the standards committee, much like the omission of copy_if. One solution, as you discovered, is to call clear() before opening another file.

Why are you reusing the ifstream object, anyway? Just put it inside the loop and let the destructor handle closing the file. The current code is fragile because someone could easily add a continue before the close() and break everything. Best practice is to limit variables to the minimum scope necessary, so if the file object is not used outside of the loop it shouldn't be declared there.

Do you know how to use a debugger? This kind of issue is trivial to solve by stepping through the code and checking failbit after each line. I strongly suggest learning about debugging, as it will save you a lot of time with future problems.
 
Last edited:

Schmide

Diamond Member
Mar 7, 2002
5,712
978
126
You might want to reverse this as well. Check for the empty sting before comparing it?

Code:
int lineNumber = 0;
while( getline( txtInFile, fileBuffer[lineNumber] ) )
{
	if ( fileBuffer[lineNumber].empty() )
	{
		continue;
	}
	if ( !strcmp( (fileBuffer[lineNumber].substr( 0, fileBuffer[lineNumber].find(' ')).c_str() ), "SDS" ) )
	{
		continue;
	}


	lineNumber++;
}
 

Gamingphreek

Lifer
Mar 31, 2003
11,679
0
81
"if (!txtInFile)" is perfectly valid. istream has an operator! implementation that checks failbit. If it didn't implement operator!, that line would just result in a compile time error.

Your problem is that getline() will set failbit if it doesn't read any data (e.g. last line of the file is empty). close() and open() do not reset failbit, so it will still be set when you attempt to open another file. As far as I know, this was just an oversight by the standards committee, much like the omission of copy_if. One solution, as you discovered, is to call clear() before opening another file.

Why are you reusing the ifstream object, anyway? Just put it inside the loop and let the destructor handle closing the file. The current code is fragile because someone could easily add a continue before the close() and break everything. Best practice is to limit variables to the minimum scope necessary, so if the file object is not used outside of the loop it shouldn't be declared there.

Do you know how to use a debugger? This kind of issue is trivial to solve by stepping through the code and checking failbit after each line. I strongly suggest learning about debugging, as it will save you a lot of time with future problems.

I know how to use the debugger extensively; however, for whatever reason, I was not able to view why a fail bit was set. We knew that for whatever reason there was a failbit set; however we were not able to figure out why.

One of the reasons, I suspect, is that each text file has >52,000 lines in it. Thus, I don't recall checking the very last line to see if the ifstream descriptor was modified in anyway.

As for allowing the variable to go out of scope with a destructor, the code would not allow it without significant modification.

The files I started with were in an hdf format. I managed to dump those into a txt based ASCII format at a significant increase in side (300%). However, the file was now in a readable format, not a complex, proprietary binary format. In short, I had 1 file for every day for 24 years. Within each ASCII file I had 52,000 lines of 6526 characters that were space delimited. Thus, I felt that reusing the ifstream pointer would be less costly than deallocating the memory and reallocating it immediately following it - perhaps I am wrong about that?

The files were named d1_YYYYMMDD - thus I had a loop for each of those values. In the innermost loop I read in 1 entire ASCII file into a string[] buffer in order to parse the values that I wanted out of them (I only needed a few columns) and into an int[][][][] array.

Thus after reading in the file, there was a lot of further loops and counters going that prevented me from quickly rewriting the code.

Finally, the code will be used 1x to extract the values that we need. It isn't my greatest coding and isn't nearly as optimized as I could make it; however, once I fix a few other bugs it will work well enough for this one time.

You might want to reverse this as well. Check for the empty sting before comparing it?

If the string is empty, the substr() function will simply not return the value I am looking for. The way the files are formatted, I will encounter the 'SDS' condition before I encounter a blank line.

Thanks
-Kevin
 

sao123

Lifer
May 27, 2002
12,653
205
106
Ok guys, I can't for the life of me figure out why this stupidly simple piece of C++ code isn't working.


The first file that it opens, it does so successfully. However, when attempting to open the second file, it outputs both "I'm open..." and "Just kidding". The getline() returns something that causes the entire while loop to test false and continue the entire loop.

Any ideas??

-Kevin

Edit: For further information -- If I start on the second file, that file opens and then the one immediately following that does not. It's like I'm allowed 1 open and close per program -_-

its definately not the getline causing anything. i eliminated that entire block of code, and was able to reproduce the same symptoms.
 

Schmide

Diamond Member
Mar 7, 2002
5,712
978
126
getline() returns a pointer to the stream. Could be a problem.

Return Value
The stream (*this).
 

Venix

Golden Member
Aug 22, 2002
1,084
3
81
getline() returns a pointer to the stream. Could be a problem.

Return Value
The stream (*this).

Right, and then operator void* is called to check the loop condition. I thought that operator void* checked eofbit, but apparently it only checks failbit/badbit. Thanks for posting this and prompting me to read the documentation again.

So I have to amend my previous explanation to remove the caveat about failbit only being set when the file ends with an empty line; your use of getline will cause failbit to be set regardless of the contents of the last line in the file. It will read to eof, set eofbit, then try to read again, which sets failbit. Sorry for the earlier oversight.

The situation I described before actually affects the istream::getline() member method, not the free function: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=351636

Oh, another thing I missed before is that you're passing ifstream::beg to open(), which is incorrect. beg is from a different enum than the one open() takes. IIRC, open() has ios_base::in as its default second parameter, so you should only need to pass the filename.
 
Last edited:

Gamingphreek

Lifer
Mar 31, 2003
11,679
0
81
Right, and then operator void* is called to check the loop condition. I thought that operator void* checked eofbit, but apparently it only checks failbit/badbit. Thanks for posting this and prompting me to read the documentation again.

So I have to amend my previous explanation to remove the caveat about failbit only being set when the file ends with an empty line; your use of getline will cause failbit to be set regardless of the contents of the last line in the file. It will read to eof, set eofbit, then try to read again, which sets failbit. Sorry for the earlier oversight.

The situation I described before actually affects the istream::getline() member method, not the free function: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=351636

Oh, another thing I missed before is that you're passing ifstream::beg to open(), which is incorrect. beg is from a different enum than the one open() takes. IIRC, open() has ios_base::in as its default second parameter, so you should only need to pass the filename.

Ah that makes sense. I feel like the documentation on the getline() function should at least make mention the conditions in which the fail bit is sit. For that matter, why use a fail bit and not simply throw an error. I could have caught the error and figured the problem out in about 2 minutes lol.

As for the ifstream::beg, I actually took the second parameter out on the open. I had it in there as a last ditch effort to try and fix this problem prior to figuring it out.

-Kevin