zychai
zychai

Reputation: 23

a quesition about c++ file I/O and fstream

I need to open a file and get the first character.If I open the file with ios::in,it will not create a file when the file doesn't exist.So when it was failed to open the file, i open the file with ios::out, it will creat a empty file, so i can input '0' to the file.

fstream passengerData;
passengerData.open("passenger.txt",ios::in);
if (!passengerData)
{
    passengerData.open("passenger.txt",ios::out);
    passengerData << '0' ; 
    passengerData.close();
}

When i run this in visual studio 2015,it can work well.But in visual c++ 6.0, it can only creat a empty file,the '0' is not input into the file.I want to know why the result is different and how to solve the problem. I also want to know how the bitwise operator OR perform when i use ios::in|ios::out or ios::in|ios::out|ios::app.

Upvotes: 2

Views: 98

Answers (2)

luk32
luk32

Reputation: 16070

The hunch that MicroVirus took on was right. I'd like to explain in detail why exactly nothing happened.

Basically, when passengerData.open("passenger.txt",ios::in); the failbit was set. Now you did retry with passengerData.open("passenger.txt",ios::out); which did succeed (sic!), although the error bits were not cleared (pre-c++11 behaviour), and made the subsequent operator<< do nothing.

I guess this was a flaw in the standard, and vc++6 is too old for c++11.

cppreference sources explaing the behaviour:

You use operator<<, which is a FormattedOutputFunction which says:

A FormattedOutputFunction is a stream output function that performs the following:

  • Constructs an object of type basic_ostream::sentry with automatic storage duration, which performs the following:

    • if eofbit or badbit are set on the output stream, sets the failbit as well [...]

So it checks whether the stream (passengerData) is operable. Now, interestingly enough, neither of eof or bad bits are set, so it seems like a wrong way, however the next step:

  • Checks the status of the sentry by calling sentry::operator bool(), which is equivalent to basic_ios::good.

Which takes you those eof-, fail-, and bad- bits. Those are iostates. In the failbit section you can find:

The failbit is set by the following standard library functions:

  • The constructors of std::basic_fstream, std::basic_ifstream, and std::basic_ofstream that takes a filename argument, if the file cannot be opened.
  • basic_fstream::open, basic_ifstream::open, and basic_ofstream::open if the file cannot be opened.

You can confirm this by checking the iostate bits after 2nd open:

fstream passengerData;
passengerData.open("passenger.txt",ios::in);
if (!passengerData)
{
    passengerData.open("passenger.txt",ios::out);
    if (passengerData.rdstate() & std::ios_base::fail) {
       std::cout << "stream has failbit set\n";
    }
    passengerData << '0' ; 
    passengerData.close();
}

Upvotes: 0

MicroVirus
MicroVirus

Reputation: 5477

From the documentation of fstream::open on cppreference it seems that it's only since C++11 that open also clear()s the flags on success, so maybe if you manually clear the flags before you call open the call will also succeed in VC++6:

fstream passengerData;
passengerData.open("passenger.txt",ios::in);
if (!passengerData)
{
    passengerData.clear();
    passengerData.open("passenger.txt",ios::out);
    passengerData << '0' ; 
    passengerData.close();
}

Also, you need to check the state of passengerData after the second call to open as well.

Upvotes: 3

Related Questions