Thread: tellg() returning -1

  1. #1
    Registered User
    Join Date
    Dec 2007
    Posts
    930

    tellg() returning -1

    tellg() won't return the size of the file, it returns -1.
    What is the reason for it?
    Code:
    #include <string>
    #include <iostream>
    #include <fstream>
    using namespace std;
    
    fstream file;
    
    int main()
    {
        // Creat file
        ofstream outfile("test.txt");
        outfile.close();
    
        string str ;
        file.open("test.txt", fstream::in | fstream::out);
        if (!file.is_open())
        {
            cerr << "Error opening file." << endl;
            return 1;
        }
    
        file << "Hello World." << endl;
        file.seekg (0, ios::beg);
    
        while(!file.eof()) 
        {
            getline(file, str); 
            cout << str << endl; 
        }
    
        file.seekg(0, ios::end);
        int newsize = file.tellg();
        file.seekg(0, ios::beg);
        cout << newsize << endl;
    
        file.close();
    
        return 0;
    }
    Last edited by Ducky; 01-30-2013 at 03:59 AM.
    Using Windows 10 with Code Blocks and MingW.

  2. #2
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    tellg returns the file position when you are reading.
    tellp returns the file position when you are writing.

  3. #3
    Registered User
    Join Date
    Dec 2007
    Posts
    930
    Ah, thank you.
    But even if I change it to seekp and tellp it returns -1.
    Apparently I do both so how to get the size of the file?
    Last edited by Ducky; 01-30-2013 at 04:17 AM.
    Using Windows 10 with Code Blocks and MingW.

  4. #4
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    Well, in addition to that, a weird quirk of file streams is that the stream has to be in good condition to allow you to do anything. You actually read the whole file, which presents a problem because now the stream is in EOF state and can't allow any further operations.

    Other than that I can get it to work for me. Sorry.
    Code:
     
    #include <fstream>
    #include <iostream>
    
    int main() {
        std::fstream file( "myfile", std::fstream::out );
        if( file.is_open() ) {
            file << "Hello world!\n";
            file.close();
        }
    
        // Open the file again:
        std::streamsize myfileSize;
        file.open( "myfile", std::fstream::in );
        if( file.is_open() ) {
    
            // Get the info.
            file.seekg( 0, std::ios::end );
            myfileSize = file.tellg();
            file.close();
        }
    
        // PROFIT.
        std::cout << "size of myfile = " << myfileSize << "\n";
        return 0;
    }
    
    // my output:
    // size of myfile = 14

  5. #5
    Registered User
    Join Date
    Dec 2007
    Posts
    930
    Yeah, but you changed the code, you closed it and reopened it again.
    I want it to be opened in read & write mode and stay open and get the size from time to time.

    We can't do that in C++ ?
    Using Windows 10 with Code Blocks and MingW.

  6. #6
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    I've never needed to do it a different way and to be honest if you want the size of the whole file, there is no difference between this and other ways. If you want to be pedantic about it, the rule for bidirectional streams is:

    read operations can only occur after the file is flushed.
    write operations can only occur after the file has been seeked.

    In addition to that, when you have to find the size of the file this way, you have to keep track of whether you are reading or writing now, in order to call the right tell function, so it is really the least feasible way.

  7. #7
    Registered User
    Join Date
    Dec 2007
    Posts
    930
    Well you can do it with fopen() and Win32 API CreateFile() so it's definitely a miss from Mr Bjarne Stroustrup.

    Ah, but I so wanted to use C++... ;-)
    Using Windows 10 with Code Blocks and MingW.

  8. #8
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    Quote Originally Posted by Ducky View Post
    Well you can do it with fopen() and Win32 API CreateFile() so it's definitely a miss from Mr Bjarne Stroustrup.

    Ah, but I so wanted to use C++... ;-)
    I didn't say you can't do it in C++. As I said before:

    Well, in addition to that, a weird quirk of file streams is that the stream has to be in good condition to allow you to do anything. You actually read the whole file, which presents a problem because now the stream is in EOF state and can't allow any further operations.
    The real trouble is the EOF state. You can fix that with fstream::clear(), but I thought you knew that.

    You still have to pay attention to what I said in my previous posts as well.

    Please do not put words in my mouth.

  9. #9
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Well you can do it with fopen() and Win32 API CreateFile() so it's definitely a miss from Mr Bjarne Stroustrup.
    O_o

    As referenced in the other thread, your ignorance is your problem.

    I promise you, you'll do just as poorly with the "WIN32API" if you don't bother to understand the library.

    Add `file.clear();' to line 30.

    Yeah, that's the only change you need to make.

    The reason you need this is exactly as whiteflags said: "the stream has to be in good condition to allow you to do anything".

    So, put simply, you have to clear the "EOF" state for `seekg' to do its job.

    Soma

  10. #10
    Registered User
    Join Date
    Dec 2007
    Posts
    930
    Ok, thanks for the explanation.
    I understand now that there is this new concept of "error control state condition" with fstream that doesnt exist with fopen() and CreateFile().
    Apparently it works completely differently than the other two.
    It can be decieving for someone who expect it to work the same way as them.

    I wonder what's the purpose of setting the stream in EOF state only for having read it.
    Last edited by Ducky; 01-30-2013 at 06:51 AM.
    Using Windows 10 with Code Blocks and MingW.

  11. #11
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    There are always quirks. See the FAQ of this board why checking eof in a loop might sometimes give you unexpected results for another one.
    You will also see that when dealing with more complex frameworks and library there is often just the right way to do things. The people that write the libraries have a certain way of usage in mind and for example there can be good reasons for fstream to have this behavior even if in this example doing something simple as getting the file size created problems.

    Note also that clearing the flag could create an error if you are relying on it later on as of course changing the read and write pointers without saving their current position. There could be a difference also if you are not opening file in binary mode. Bottom line is depending on the usage in the end reopening the file could be the best way to go. Or just keep track what you write by deriving a custom class from fstream so it keeps track or something simpler. Point being that there is no standard function to get the size so you just need to take everything under consideration.

  12. #12
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    Note that this:
    Code:
    while(!file.eof())
    {
        getline(file, str);
        cout << str << endl;
    }
    is not the proper way to read through a file. The end-of-file condition is only set after an attempt to read from the file has failed. This means that up to and including the last line of the file, this test will return false and the loop will continue as expected. However, once that last line has been read, the test will still return false one more time since we have not yet done the read in the body of the loop which would set the EOF condition. Once this read is attempted - and fails - then the end-of-file condition will be set and the test would return true causing the loop to exit. The problem is that at that point we are already in the body of the loop and committed to our processing within said loop. For you, all this means is you attempt to output what you've just read... a read operation that has just failed. The most likely outcome here is that the last line of the file gets output twice.

    The solution to this is to test the read operation as the exit condition and not to directly test the return result of a call to the stream's eof function. This looks like the following:
    Code:
    while(getline(file, str))
    {
        cout << str << endl;
    }



    I wonder what's the purpose of setting the stream in EOF state only for having read it.
    Well, once you've finished reading all the data in the file, you're at the end of the file right?
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  13. #13
    Registered User
    Join Date
    Dec 2007
    Posts
    930
    Thanks but getline() sets bits too so you still need to clear it.

    "A call to this function may set any of the internal state flags of is if:"

    flag error
    eofbit The end of the source of characters is reached during its operations.
    failbit The input obtained could not be interpreted as a valid textual representation of an object of this type.
    In this case, distr preserves the parameters and internal data it had before the call.
    Notice that some eofbit cases will also set failbit.
    badbit An error other than the above happened.
    Last edited by Ducky; 01-30-2013 at 08:11 AM.
    Using Windows 10 with Code Blocks and MingW.

  14. #14
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    Quote Originally Posted by Ducky View Post
    It can be decieving for someone who expect it to work the same way as them.
    why would you expect it to work the same way? they are two totally different systems, developed from vastly different ideologies. the fact that they are designed to generally do the same thing - read and write files - is of little consequence.

    Quote Originally Posted by Ducky View Post
    I wonder what's the purpose of setting the stream in EOF state only for having read it.
    the EOF flag gets set when you try to perform a read operation after you've reached the end of the file. simply reaching the end doesn't set the state. an EOF state for writing doesn't make sense, because it's a perfectly reasonable idea to continue writing after the current end of a file. don't you think you'd also check the return value of feof() if you were reading from the file using c-style FILE* functions? that's just common sense.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Returning an integer ... not returning; weird error
    By Imanuel in forum C++ Programming
    Replies: 19
    Last Post: 09-25-2011, 01:30 PM
  2. Replies: 5
    Last Post: 09-06-2011, 02:59 PM
  3. CSV read problem usng tellg()
    By rogster001 in forum C++ Programming
    Replies: 1
    Last Post: 06-02-2011, 06:01 AM
  4. Recursion: base case returning 1, function returning 0
    By yougene in forum C Programming
    Replies: 5
    Last Post: 09-07-2007, 05:38 PM
  5. tellg and seekg
    By Zoalord in forum C++ Programming
    Replies: 1
    Last Post: 01-11-2004, 02:45 PM