C++: .eof on an empty file - c++

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.

Related

Is there a character that can be used as a delimiter for EOF?

I wrote a function that spellchecks a line read from a file which takes in a file stream and a delimiter as parameters. My problem is that the function requires a delimiter, but when reading in the last line, I haven't got one. I would use the last character of the file, but I need that last character for spellcheck purposes.
Is there any way to use the EOF macro as a delimiter?
Typically, you would let the stream tell you when it has received an EOF signal in whatever platform-dependent way is appropriate (be that the end of a file, or Ctrl+D on a Linux terminal emulator).
So, stop reading when you hit your custom delimiter, or when an attempt to read from the stream sets the stream's EOF bit. You ought to be checking the stream's state anyway — what if there's an error? You'll be looping forever at the moment.
That's how std::getline and co do it, anyway.

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

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)) {
// ..
}

Use of eof() in files in C++

Can anybody explain how this while condition works while accessing files in C++. In the while condition, employeeLine is a string.
while ( !inFile.getline( employeeLine, MAX_LINE, ‘\n’ ).eof( ) )
{
//some code here
}
If the file contains data like this then
will the code process the last line data or not as there is no newline character
Tomb33bb9.75<\n>
bbMarybb26bb10.15
(eof)
First of, inFile.getline(...) return the stream, i.e., a reference to inFile. When the stream reaches the end of file, the flag std::ios_base::eofbit gets set and inFile.eof() returns true. While there is any input, this flag won't be set. If the last line is incomplete, i.e., is lacking a newline character, it won't be processed!
Note, however, that the end of file may not necessarily be reached: if something goes wrong, std::ios_base::failbit is set and the stream won't response to any further attempts to read something: you'd have an infinite loop. std::istream::getline() does set std::ios_base::failbit when the line is too long to fit into the buffer (i.e., there are more than MAX_LINE - 1 characters). Another potential situation where the stream may go into failure mode without setting std::ios_base::eofbit is when an exception is thrown from the used stream buffer.
In general a better approach is to rely on the conversion to bool for a stream, i.e., to use
while (inFile.getline(employeeLine, MAX_LINE)) {
// ...
}
There is no need to pass '\n' as last parameter as it is the default. There is also no harm.
Note, that the above code won't deal with lines longer than MAX_LINE. That may be intentional, e.g., to avoid a denial of service attack based on infinitely large lines. Typically, it is preferable to use std::string, however:
for (std::string line; std::getline(inFile, line); ) {
// ...
}
If "inFile.getline( employeeLine, MAX_LINE, ‘\n’ ).eof( )" returns TRUE, it means that we reach the end of "inFile". So "!inFile.getline( employeeLine, MAX_LINE, ‘\n’ ).eof( )" means that we do not reach the end of "inFile".
See details in MSDN

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.