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

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.

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.

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();
}

Related

C++ open() not working for any apparent reason

ifstream infile;
infile.open("BONUS.txt");
string info;
if (!infile)
cout << "File Open Failure" << endl;
else
{
while (infile >> info)
cout << info << endl;
infile.close();
}
This is my code. And no matter what I do, my file always fails to open. It enters the if and exits. What could possibly be the problem? My text file is saved in the correct directory and nothing seems to be wrong with it.
There are two parameters in open(), file to be opened and mode. The mode refers to what you can do with that file, i.e. write to, read from, etc.
There are six possible modes when using open():
Parameter in stands for input. The internal stream buffer enables input. (Use for reading the file.)
Parameter out stands for output. The same internal buffer enables output. (Use for writing to the file.)
Parameter binary allows all operations to be done in binary, instead of text.
Parameter ate stands for at end and begins output at the end of the file.
Parameter app stands for append and output events happen at the end of the file.
Parameter trunc stands for truncate. All contents in existence before it is opened are deleted.
It seems that you want to write to the file, in which case use out.
ifstream infile;
infile.open("BONUS.txt", out);
If you are not using the correct mode, the function will fail. If you have any more questions, Google fstream::open().

input from a file using get line

I am trying to read from a file, and I have separated them by a new line character. I am using these code :
fstream input("wordfile.dat", ios::in);
char b[10];
while (!input.eof())
{
input.getline(b, 10);
cout << b << endl;
}
If I change the loop statement from while(!input.eof()) to while(input) , the program will output a blank line before the loop ends. But now it won't. The question is, in both statements the while condition must first input a line and by inputting it, it will know if it has reached end of file or if there is still more information. So input.eof() must act just like the other statement and output a blank line. First I thought it was a mistake, but I wondered why it was acting correctly. What is the difference between these two conditions?
Looking at operator bool we see ...
Notice that this function does not return the same as member good [...]
... that if (stream) is not the same as if (stream.good()), but also learn that it ...
Returns whether an error flag is set (either failbit or badbit).
So it's basically the same as not stream.fail() (which is true if either failbit or badbit is set).
This also explains the different behavior between while (stream) and while (not stream.eof()):
When the input file does not end with a newline, then stream.getline(buffer, size) will encounter the end of file before reaching the delimiting newline character (or the 10 character limit) and thus set the eofbit. Testing the stream with its operator bool will then be still true (since neither failbit nor badbit are set), and only after trying to read more using getline will set the failbit since no characters are extracted.
But when testing with not stream.eof(), the eofbit alone will end the loop.
If the stream is good, which is what you're testing with,
if (stream) // ...
then, this means that the stream is neither at the end of file (eof), nor bad nor failed.
So when it's not at the end of file, then it could still have failed or be in a bad state.
See the table here.
When reading (or writing) a stream, test for good unless you have a specific reason not to do so.
As a side note, this happens when you do input like the following, since getline returns a reference to the instance it's called on:
while (stream.getline(buffer, size)) {
// ..
}

Should ofstream throw exception when folder name is input?

I want to generate file through ofstream, here are the codes.
void testOfstream(string filename){
ofstream ofs(filename, ofstream::out | ofstream::trunc | ofstream::binary);
char body[] = { 'a', 'b', 'c' };
ofs.write(body, sizeof(body)/sizeof(char));
ofs.close();
}
If the parameter filename is C:\\MyProject\\CodeTest2010\\CodeTest2010\\test.txt, the test.txt file is created successfully.
If the parameter filename is C:\\MyProject\\CodeTest2010\\CodeTest2010\\, or C:\\MyProject\\CodeTest2010\\CodeTest2010, nothing is changed in the folder CodeTest2010. I think it should throw exception to warning that the input file name is invalid.
My question is why it keeps silence instead of throwing exception, when the input file is folder not a filename?
According to this, I do not find any information about the folder name is input into ofstream.
IOStreams by default do not throw exceptions. Instead they delegate error indication to a bitmask type representing certain stream errors. The inability to open a file is classified as a recoverable error and therefore it sets std::ios_base::failtbit in its stream state. You can enable exceptions by specifying this bit in the parameters of the exceptions() method:
ofs.exceptions(std::ios_base::failbit);
Actually if you click through to the description of the constructor you'll see that:
If the file cannot be opened, the stream's failbit flag is set.
The default behaviour of iostreams is precisely this: failed operations do not throw exceptions but can be detected by checking the stream status bits. You can arrange for the stream to throw exceptions on failed operations using the ios::exceptions function although this doesn't apply to the constructor (since you have to construct the stream before you can call that function).

C++: .eof on an empty file

Lets see this program:
ifstream filein("hey.txt");
if(filein.eof()){
cout<<"END"<<endl;
}
Here "hey.txt" is empty. So the if condition here is thought should have been true But it isnt
Why isnt the eof returning true although the file is empty?
If i added this before the if the eof returns true although arr is still empty and the file is still empty so both unchanged
char arr[100];
filein.getline(arr,99);
eof() function returns "true" after the program attempts to read past the end of the file.
You can use std::ifstream::peek() to check for the "logical end-of-file".
eof() tests whether the "end of file" flag is set on the C++ stream object. This flag is set when a read operation encouters the end of the input from the underlying device (file, standard input, pipe, etc.). Before you attempt a read on an empty file the flag is not set. You have to perform an operation that will try to read something before the flag will be set on the stream object.
The flag std::ios_base::eofbit is set when reaching the end of a stream while trying to read. Until an attempt is made to read past the end of a stream this flag won't be set.
In general, use of std::ios_base::eofbit is rather limited. The only reasonable use is for suppressing an error after a failed read: It is normally not an error if a read failed due to reaching end of file. Trying to use this flag for anything else won't work.

Failing to read file loaded with ifstream

void bot_manager_item::create_games()
{
games.clear();
std::ifstream paths_in("C:\\Users\\bill hank\\Documents\\bot_plugins\\directory_listing.txt", std::ios::in);
while (paths_in.good())
{
send_message("The path was good.");
char q[5000];
paths_in.getline(q, 5000);
send_message(q);
games.push_back(qanda(q));
}
paths_in.close();
}
The file I'm loading exists, what else might be wrong? paths_in.good keeps failing.
Edit: I figured it out. Wow am I annoyed by the answer to this. Basically Windows lets you say whether you want to show file extensions or not. This windows installation is set to say that the extension shouldn't be shown. So when I'm checking the file again and again I'm seeing: directory.txt and thinking that this means that everything is fine with the directory when in reality the filename was directory.txt.txt
If paths_in.good() keeps failing then it means that some of the stream error flags are set (badbit, eofbit or failbit).
eofbit - end of file was reached
badbit - error with the stream buffer such as memory shortage or an exception inside the stream buffer is cast
failbit - some other error beside eof was reached
In order to find out what happened, you need to check which errorbit is set first, and then find out more about the specific error, and what can cause it.
Out of curiosity, does this code output the contents of the file correctly? If this code works, then the problem is something else. If this code doesn't work, then that likely means that the file either isn't where you specified, or you don't have read permissions on it.
void bot_manager_item::create_games() {
std::ifstream paths_in("C:\\Users\\bill hank\\Documents\\bot_plugins\\directory_listing.txt");
char q[5000];
while (paths_in.getline(q, 5000)) {
std::cout << q << std::endl;
}
}
This code does a few minor things differently.
std::ios::in doesn't need to be explicitly specified for std::ifstream.
it doesn't use is_good, while that should be fine, you can just treat the std::ifstream as a bool which will be true when it is in a good state.
getline() returns a reference to the stream it operated on, so you can just put that whole line in the condition.
cosmetic, but no need to explicitly close the ifstream if it is about to go out of scope.