tellg() moves unexpectedly

I am writing a program with a class that has an fstream member. The functions for the class is to open a file, read and print the last line of a file, and close a file. The functions work for the first file but not when I open a second or third file - it does not matter what file I use it is always the second one that has the error. This program works fine on Linux but not on Windows. I have tried opening the files in binary and the same problem still occurs.

After I open the second file, I go through my get(char) function once, and my tellg() randomly moves from 17 to -1 instead of from 17 to 18. Can anyone help me figure out why this is?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
void Files::getLastLine(){
    bool searchForStartLine = true;
    char location;
    
    //If its open
    if(accountFile.is_open()){
        
        //Go back one space
        accountFile.seekg(-1, ios::cur);      
        
        //While I want to search for the start of a line
        while (searchForStartLine == true){
            
            //Get the character of tellg
            accountFile.get(location);
            
            
            //If tellg is <=1 then its at the start so stop looking
            if (accountFile.tellg() <= 1){
         
                //set seekg to start
                accountFile.seekg(0);
                
                //stop looking
                searchForStartLine = false;
                
            }
            //see if its at a new line
            else if (location == '\n'){
                
                //if it is then stop
                searchForStartLine = false;
                
                
            }
            //if its not at the start or new line 
            else{
                //move back to start of char and then back one more to get the next char
                accountFile.seekg(-2,ios::cur);
            }
        }
        //get the line of the file
        getline(accountFile, strLastLine);
    
        cout << strLastLine << "\n";
    }
    
    }


I have checked and the first file does work completely and the last line gets printed. It also closes completely. The second file also opens completely but has its tellg() reset after the get(char) function.

To open my first file the function is :
1
2
3
4
void Files::openFile1(){
    //opens one file
    accountFile.open("File1", fstream::out | fstream::in | fstream::ate);
}


To close the file my function is:
1
2
3
4
5
void Files::closeFile(){
    //Close the file
    accountFile.close();
    accountFile.flush();
}


and to open my second file the function is:
1
2
3
4
void Files::openFile2(){
    //opens one file
    accountFile.open("File2", fstream::out | fstream::in | fstream::ate);
}
Open your files in binary mode and account for the line ending combination on Windows, otherwise only seekg to locations returned by tellg.
I go through my get(char) function once, and my tellg() randomly moves from 17 to -1

tellg() doesn't "move to -1". It fails, and returns -1 to indicate that it failed. It can fail for several reasons, one of which is that the stream already has the failbit set. Start by checking if each of your I/O operations (get(), getline(), seekg(), tellg()) fail (for debugging purposes, you could print accountFile.fail() after each operation)

(and yes, relative seeks aren't expected to work on files opened in text mode)
I think this could be a possible problem where fstream fail:
1
2
3
4
5
6
void Files::closeFile(){
    //Close the file
    accountFile.close();
    accountFile.flush();
}



Please remove the flush() call after you call close() and call clear() before opening another file to reset possible fstream errors.
So I found out that the get() function was failing for the second file, and adding a blank line at the end of the text files makes the program work, but I do not know why.

so if the files look like this
file1:
"text"
"Blank line" EOF.
then it works.

but if the files look like this
file1:
"text" EOF.
it doesn't work.
Last edited on
That's just what istream::get() does, it sets failbit (and eofbit) if it fails to read a character because the stream is at end of file.
I guess I am just confused then why it works for the first file but not the second file unless there is a blank line at the end of the first file
Those functions just aren't built for this kind of usage. Why not just read the file line by line and print the last non-blank line?
1
2
3
4
5
string line,  result;
while(getline(accountFile,  line)) 
    if(! line.empty()) 
        result = line;
cout << result << '\n' ;

Yeah that makes more sense. Just trying to learn why the error occurred even though you've shown it's not the best way to go about it.

EDIT: Figured it out. The streams EOF flag was set in Windows after the first file was read and needed to be reset with the clear() function. Thanks.
Last edited on
Topic archived. No new replies allowed.