0

I have a pretty simple code:

void LookupName( string tname ){ //Checks for name in records.txt and enters it if it does not exist

//Variables
string fname; //Used to store the name
string throwaway; //Used to dispose of extra data
bool found = false; //Used to track if a name is found in the file

//objects
fstream file ( STATS_FILE ); //Open the file

if (file.is_open()) {

    while ( !file.eof() ) {
        getline (file, fname, DELIM); //Fill name
        getline (file, throwaway, '\n'); //throw away rest of line

        cout << "Found: " << fname << " tname: " << tname << '\n';
        Pause();

        if ( fname == tname ) { //Otherwise, continue
            cout << "Found: " << fname << " tname: " << tname << '\n';
            Pause();
            found = true;
        }
    }

    if ( found == false ) { //if the name is not found
        //Reopen the file so that we can write to it
        file.close();
        file.open( STATS_FILE, fstream::in | fstream::out | fstream::app );

        cout << "Not found" <<endl;
        Pause();
        file << tname << ",0,0\n"; //Add it to the file with 0 wins and losses
    }

    //Cleanup
    file.close();
} 
}

This works, but if you notice at the bottom when I check to see if the name is found, I have to close and re-open the file.

The follow will not work for some reason:

void LookupName( string tname ){ //Checks for name in records.txt and enters it if it does not exist

//Variables
string fname; //Used to store the name
string throwaway; //Used to dispose of extra data
bool found = false; //Used to track if a name is found in the file

//objects
fstream file ( STATS_FILE, fstream::in | fstream::out | fstream::app ); //Open the file

if (file.is_open()) {

    while ( !file.eof() ) {
        getline (file, fname, DELIM); //Fill name
        getline (file, throwaway, '\n'); //throw away rest of line

        cout << "Found: " << fname << " tname: " << tname << '\n';
        Pause();

        if ( fname == tname ) { //Otherwise, continue
            cout << "Found: " << fname << " tname: " << tname << '\n';
            Pause();
            found = true;
        }
    }

    if ( found == false ) { //if the name is not found
        cout << "Not found" <<endl;
        Pause();
        file << tname << ",0,0\n"; //Add it to the file with 0 wins and losses
    }

    //Cleanup
    file.close();
} 
}

I'm curious to know why it doesn't work in the second example as it seems more efficient to open the file only 1 time with the correct flags, do what I need to do and close it.

I have a feeling this might have something to do with the position of the cursor, I have atttempted to use something like file.seekg(0) and file.seekg(0, ios_base::beg) but they don't seem to work as advertised (or I just mis understood the advertisement).

any input would be appreciated.

Edit: The couts were for debugging.

Edit 2: I Suppose I should emphasize the question a little more.

The problem is that the second example does not write to the file where as the first one does. I understand that there might be some concern regarding the !file.eof() condition but in this instance I don't care if it runs an extra time as it wont negatively effect the outcome (additionally, the text file that is being read from has been formatted correctly so that this won't happen).

Edit 3: I created a very small program that ran:

   //Testing bs
fstream file("Test.txt", fstream::in | fstream:: out | fstream::app );
string temp;

//ClearScreen
system(CLEAR_SCREEN);


file << "Line one\n";

getline(file, temp);
file << temp;
file << "Line two\n";

Pause();
return Menu;

Only the first line is written to the file. I'm betting that getline is changing the mode of the stream which is why it is unwritable afterwords.

Final Edit: after a bunch of research it appears that in the above situation, re-opening the file is the best resolution. Ultimate,y the issue is in the use of getline() vs file.getline(). I'd have to rewrite far too much of the 1000 lines of the program to do it "correctly." Moral of the story? if you are having this issue, spend some time researching the difference between istream::getline and getline(string) and learn to identify when you are going to use which so that you don't get stuck in this situation. Fortunately, it's not imperative I fix it now, but it might be for others in the future.

gNerb
  • 867
  • 2
  • 12
  • 28
  • You might want to start by reading http://stackoverflow.com/questions/14615671/whats-the-real-reason-to-not-use-the-eof-bit-as-our-stream-extraction-condition?rq=1 – Tony Delroy Dec 09 '13 at 07:32
  • @TonyD Plenty of good information thanks; however, that is entirely unrelated to the question. I'm not flagging your comment, but i'm not up voting it either, for what ever that is worth. – gNerb Dec 09 '13 at 07:37
  • 1
    open the file in binary mode instead, then seekg will work "as advertised" – AndersK Dec 09 '13 at 07:55
  • @claptrap I'm sure you are correct; however, that didn't appear to be the solution to the overall problem. Thank you for the tip. – gNerb Dec 09 '13 at 08:17
  • @Toby - with broken code like `while ( !file.eof() )`, you can't expect the rest to work properly until that's fixed... – Tony Delroy Dec 09 '13 at 09:55

1 Answers1

0

I can't give you a definite answer, but I can give you a pretty good idea, based on inferences.

You are using fstream (file stream), instances of which are used for dealing with files. If you take a look at the documentation for fstream.open (link), notice that the second parameter is set up such that, by default, it will be either inputting or outputting to a file. Notice that the default is one or the other. This means that you can't assume, when you open the file, that the file exists. More importantly, since you might be inputting from the file, from the perspective of fstream, it shouldn't be assumed that if the file doesn't exist, it should be created.

Another way to think of it: I will assume that you are familiar with ifstream (input file stream) and ofstream (output file stream), which are generally introduced earlier in C++ tutorials/guides than fstream. If you take a look at the documentation for ifstream (link) and for ofstream (link), you'll notice that both of them derive from fstream. Now remember that when you call ifstream.open, if the file doesn't exist, it isn't created - rather, the failbit is set. Contrastingly, when you call ofstream.open, if the file doesn't exist, it is created.

Now, since ifstream and ofstream both derive from fstream, we have two possibilities:

  1. ofstream.open derives directly from fstream.open (ie it has no extended functionality), and we can reasonably expect fstream.open to create file, given that it doesn't exist at first
  2. ifstream.open derives directly from fstream.open, and we can reasonably expect fstream.open not to create a file, given that it doesn't exist at first

It should go without saying that both of these cannot be true; ofstream.open and ifstream.open cannot both derive from the same thing and yet differ in what they do; fstream.open cannot both do and not do something.

If you think about it, the second option is more likely, and here is why: If ofstream.open doesn't directly derive from fstream.open, all it has to do is add an extra step, in which it creates the file if it doesn't exist, and resets the failbit. All of the preceding behavior can be achieved by calling the open function of the parent class. On the other hand, if ifstream.open doesn't directly derive from fstream.open (implying that fstream.open creates the file, given that it doesn't exist at first), ifstream.open must be a complete re-implementation; otherwise there would be no way to skip the step in which the non-existent file is created.

Since it would be less efficient to have a function which re-implements so much than having a different function which simply adds something on, it's more likely that fstream.open doesn't create/open a file if it doesn't already exist.

I realize that this might not be a definitive solution to your problem, but I think this should explain why the second block of code you posted wouldn't (and shouldn't) work. When I look at your first code block (which you said works) I'm not entirely sure what about it makes it work, but I would guess it has something to do with your addition of | fstream::append to the open mode parameter of fstream.open.

I hope this helped.

Brian Gradin
  • 2,165
  • 1
  • 21
  • 42
  • I apologize but it seems as though your claiming the first one works for exactly the same reason the second one doesn't. They both have fstream::app in them. The only difference is where the mode appears. The first one appears after I have already run through the entire file, the second one appears before. As far as I have been able to tell (it's not listed on cplusplus.com) fstream default is ios_base::in | ios_base:;out meaning in it's default state I should be able to write to and read from the file. – gNerb Dec 09 '13 at 08:05
  • Right - but only if the file already exists. It's not going to create the file if it doesn't already exist - that was the point of my post. I only mentioned `fstream::append` because I thought your use of it *might* be the reason certain things were working and others weren't. But as you pointed out, you have it where you open the file in the second block of code, too. So that's probably not it. – Brian Gradin Dec 09 '13 at 15:04
  • Is the second block of code failing to run even if the file you are opening exists? – Brian Gradin Dec 09 '13 at 15:05
  • Another thought - in the second block of code, you have `while (!in.eof())` before trying to output to the file, which basically guarantees that the eof bit will be set when you try to output to the file. This ~may~ result in unexpected behavior. In other words, you may not be able to output to the file when the eof bit is set. Try calling `fstream::clear` right before trying to output - this will reset the error flags. – Brian Gradin Dec 09 '13 at 15:10