Reading from text file until EOF repeats last line [duplicate] - c++

This question already has answers here:
Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?
(5 answers)
Closed 4 years ago.
The following C++ code uses a ifstream object to read integers from a text file (which has one number per line) until it hits EOF. Why does it read the integer on the last line twice? How to fix this?
Code:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream iFile("input.txt"); // input.txt has integers, one per line
while (!iFile.eof())
{
int x;
iFile >> x;
cerr << x << endl;
}
return 0;
}
input.txt:
10
20
30
Output:
10
20
30
30
Note: I've skipped all error checking code to keep the code snippet small. The above behaviour is seen on Windows (Visual C++), cygwin (gcc) and Linux (gcc).

Just follow closely the chain of events.
Grab 10
Grab 20
Grab 30
Grab EOF
Look at the second-to-last iteration. You grabbed 30, then carried on to check for EOF. You haven't reached EOF because the EOF mark hasn't been read yet ("binarically" speaking, its conceptual location is just after the 30 line). Therefore you carry on to the next iteration. x is still 30 from previous iteration. Now you read from the stream and you get EOF. x remains 30 and the ios::eofbit is raised. You output to stderr x (which is 30, just like in the previous iteration). Next you check for EOF in the loop condition, and this time you're out of the loop.
Try this:
while (true) {
int x;
iFile >> x;
if( iFile.eof() ) break;
cerr << x << endl;
}
By the way, there is another bug in your code. Did you ever try to run it on an empty file? The behaviour you get is for the exact same reason.

I like this example, which for now, leaves out the check which you could add inside the while block:
ifstream iFile("input.txt"); // input.txt has integers, one per line
int x;
while (iFile >> x)
{
cerr << x << endl;
}
Not sure how safe it is...

There's an alternative approach to this:
#include <iterator>
#include <algorithm>
// ...
copy(istream_iterator<int>(iFile), istream_iterator<int>(),
ostream_iterator<int>(cerr, "\n"));

Without to much modifications of the original code, it could become :
while (!iFile.eof())
{
int x;
iFile >> x;
if (!iFile.eof()) break;
cerr << x << endl;
}
but I prefer the two other solutions above in general.

The EOF pattern needs a prime read to 'bootstrap' the EOF checking process. Consider the empty file will not initially have its EOF set until the first read. The prime read will catch the EOF in this instance and properly skip the loop completely.
What you need to remember here is that you don't get the EOF until the first attempt to read past the available data of the file. Reading the exact amount of data will not flag the EOF.
I should point out if the file was empty your given code would have printed since the EOF will have prevented a value from being set to x on entry into the loop.
0
So add a prime read and move the loop's read to the end:
int x;
iFile >> x; // prime read here
while (!iFile.eof()) {
cerr << x << endl;
iFile >> x;
}

At the end of the last line, you have a new line character, which is not read by >> operator and it is not an end of file.
Please, make an experiment and delete the new line (thelast character in file) - you will not get the duplication.
To have a flexible code and avoid unwanted effects just apply any solution given by other users.

int x;
ifile >> x
while (!iFile.eof())
{
cerr << x << endl;
iFile >> x;
}

Related

C++ question regarding how ifstream reads lines and columns

I was reading some old codes of mine and I realize that I don`t know exactly how ifstream works. The following code should just read a file, save its contents into an object and create another file with exactly same data, which is written as:
#include <iostream>
#include <fstream>
using namespace std;
class grade {
public:
float grade1;
float grade2;
float grade3;
};
void read_file(grade data[]){
ifstream myfile("data.txt");
int i=0;
while(myfile >> data[i].grade1){
myfile >> data[i].grade2 >> data[i].grade3;
i=i+1; }
myfile.close();
myfile.clear();
}
void write_file(grade data[]){
ofstream myfile("data_out.txt");
for(int i=0; i<3; i++){
myfile << data[i].grade1 << "\t" << data[i].grade2 << "\t" << data[i].grade3 << endl;
}
myfile.close();
myfile.clear();
}
int main()
{
grade data[3];
read_file(data);
write_file(data);
return 0;
}
With "data.txt" having:
23.5 10.1 11.6
14.3 8.2 9.3
6.5 6.7 5.3
The code works just fine, but I don't get how the ifstream "knows" which line or column it should be at a given moment, since the variable i is not used to control myfile. I am assuming that by default ifstream has two internal variables, one for line and the other for column, that each time a myfile >> xxx command is identified, the column variable is incremented and every time that a loop repeats the line variable is incremented.
It is something like that? Not actually controlling what line or column the code is at a given moment is quite confusing to me.
Lets say, for instance, that in this example I would like to read only the data on the second line and column. Could I access directly it using some explicit expression like 'myfile[1][1] >> xxx'? I guess that getlinecould be used, but since it is used for strings I really don't know.
In read_file() the reading occurs in this loop:
int i=0;
while(myfile >> data[i].grade1){
myfile >> data[i].grade2 >> data[i].grade3;
i=i+1; }
First, this assumes that data[] was already allocated with sufficient number of elements. It's strange since the file was not yet read, so how to know how many records are to be read in advance?
Then, this reading algorithm assumes that the data is in an ordinary text file, in which data elements are space separated:
The myfile >> data[i].grade1 reads the first grade of a new sequence. If it reaches the end of file, the result will be evaluated to false and the loop will end.
Then for every first grade read, the loops reads the next grades of the record: myfile >> data[i].grade2 >> data[i].grade3;
This logic reads in fact one number after the other. The only constraint is that there are one or several spaces between the numbers. The stream therefore doesn't care about columns: it's just the next item to be read.
The following input file would work equally well:
23.5
10.1
11.6
14.3 8.2
9.3 6.5 6.7 5.3
This being said, no need to close and clear the stream at the end of the function: when the function will return, its local objets will be destroyed. This includes the stream object, and the destruction ensures that everything ends right.
Remark: incomplete records are not handled well: if the first grade is present but one of the remaining is missing, the stream will be in an error state, and the grade2 or grade3 elements will be left uninitialized.

why does eof() not work as I expect?

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream in("input.txt");
int i = 0,sum=0;
char x;
while (!in.eof()){
in >> i;
if (in.good()) {
cout << "integer is " << i << endl; sum += i;
}
if (in.fail()) {
in.clear();
in >> x;
cout << "the char is " << x << endl;
}
}
cout << sum;
char z;
cin >> z;
}
and my input.txt is like:
bear: sdf 23 okI am fine 11q , 45
and my screen output is like:
the last number 45 doesn't show up
So what happened here? why 45 is regarded as one out of file. And if I add a 's' immediately right next to 45, the screen will have two s showing up, rather than just one.
The problem is that when extracting symbols for 45,it tries to extract symbol after '5' (to check if number continues further) and sees end of file, setting eofbit. This makes in.good() test to fail. Suggestions:
while (!in.eof()){
in >> i;
if ( in ) { //Not .good(), just conversion to bool
Or
while (!in.eof()){
if ( in >> i; ) { //both extraction and checking in same operation
Remember, .good() is not the same as checking stream state. .good() is telling if stream ready for further input. Bool conversion does ! .fail() and checks if last operation was executed succesfully
Well, "eof()" does work as expected, at least, how I expect it to work: it gets set when the stream somehow touches the end of file. If your file's last line actually ends with '5' rather than a newline, reading an integer stops due to touching newline and std::ios_base::eofbit gets set. Since std::ios::good() returns false if any bit is set, include std::ios_base::failbit the last value wouldn't be printed.
In general, eof() is more often misused than appropriately used. Essentially the only reasonable uses of eof() is to verify if the entire stream was consumed or to suppress an error message if eof() is set as it is expected that input fails at the end of the stream. Likewise, there is generally little use for std::ios::good().

C++ reading from file - last element gets read twice [duplicate]

This question already has answers here:
Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?
(5 answers)
Closed 4 years ago.
The following C++ code uses a ifstream object to read integers from a text file (which has one number per line) until it hits EOF. Why does it read the integer on the last line twice? How to fix this?
Code:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream iFile("input.txt"); // input.txt has integers, one per line
while (!iFile.eof())
{
int x;
iFile >> x;
cerr << x << endl;
}
return 0;
}
input.txt:
10
20
30
Output:
10
20
30
30
Note: I've skipped all error checking code to keep the code snippet small. The above behaviour is seen on Windows (Visual C++), cygwin (gcc) and Linux (gcc).
Just follow closely the chain of events.
Grab 10
Grab 20
Grab 30
Grab EOF
Look at the second-to-last iteration. You grabbed 30, then carried on to check for EOF. You haven't reached EOF because the EOF mark hasn't been read yet ("binarically" speaking, its conceptual location is just after the 30 line). Therefore you carry on to the next iteration. x is still 30 from previous iteration. Now you read from the stream and you get EOF. x remains 30 and the ios::eofbit is raised. You output to stderr x (which is 30, just like in the previous iteration). Next you check for EOF in the loop condition, and this time you're out of the loop.
Try this:
while (true) {
int x;
iFile >> x;
if( iFile.eof() ) break;
cerr << x << endl;
}
By the way, there is another bug in your code. Did you ever try to run it on an empty file? The behaviour you get is for the exact same reason.
I like this example, which for now, leaves out the check which you could add inside the while block:
ifstream iFile("input.txt"); // input.txt has integers, one per line
int x;
while (iFile >> x)
{
cerr << x << endl;
}
Not sure how safe it is...
There's an alternative approach to this:
#include <iterator>
#include <algorithm>
// ...
copy(istream_iterator<int>(iFile), istream_iterator<int>(),
ostream_iterator<int>(cerr, "\n"));
Without to much modifications of the original code, it could become :
while (!iFile.eof())
{
int x;
iFile >> x;
if (!iFile.eof()) break;
cerr << x << endl;
}
but I prefer the two other solutions above in general.
The EOF pattern needs a prime read to 'bootstrap' the EOF checking process. Consider the empty file will not initially have its EOF set until the first read. The prime read will catch the EOF in this instance and properly skip the loop completely.
What you need to remember here is that you don't get the EOF until the first attempt to read past the available data of the file. Reading the exact amount of data will not flag the EOF.
I should point out if the file was empty your given code would have printed since the EOF will have prevented a value from being set to x on entry into the loop.
0
So add a prime read and move the loop's read to the end:
int x;
iFile >> x; // prime read here
while (!iFile.eof()) {
cerr << x << endl;
iFile >> x;
}
At the end of the last line, you have a new line character, which is not read by >> operator and it is not an end of file.
Please, make an experiment and delete the new line (thelast character in file) - you will not get the duplication.
To have a flexible code and avoid unwanted effects just apply any solution given by other users.
int x;
ifile >> x
while (!iFile.eof())
{
cerr << x << endl;
iFile >> x;
}

How to read in each line from a file c++ [duplicate]

This question already has answers here:
Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?
(5 answers)
Closed 9 years ago.
I have two questions. I'm trying to read in line by line from a file but I can't get each line to go individually to where I can use it. Also, I can't figure out how to ask the user for their file name and than use what they type in the program. All the examples I've found just has the name of the file in the code already and just putting it in cin doesn't seem to work. I am trying to separate two different types of lines, so for example, abcd and 1234. If the first value is a letter do case a, if it's a number, do case b. But all I've managed to do is have getline have everything in one so I can't actually separate it. Anyone have any advise?
string x;
cout << "Enter your file: " ;
cin >> x
string line;
ifstream myfile;
myfile.open (x);
while(!myfile.eof())
{
getline(myfile,line, ' ');
}
cout << line << endl;
There is nothing wrong with your cin statement for reading the file name. As long as the file exists, what you have will open the file. Though, you can add some error checking to it:
std::string x;
std::cout << "Enter your file: " ;
if (!(std::cin >> x))
{
std::cerr << "Invalid input!" << std::endl;
return -1;
}
std::ifstream myfile(x);
if (myfile.is_open())
{
std::string line;
while (myfile >> line)
{
std::cout << line << std::endl;
}
}
else
{
std::cerr << "Unable to open file: " << x << std::endl;
return -1;
}
Note the proper while condition (do not use eof() for std::istream while conditions!). Additionally, if you are separating on whitespace, there is no need to use std::getline - operator>> will do the same thing.
If you want to do different things based on what the value of line is, then check the string. For example:
if (line[0] >= '0' && line[0] <= '9')
// do something with digits
else
// do something with non-digits
First, don't put eof() in while condition. It's wrong because iostream::eof will only be set after reading the end of the stream. It does not indicate, that the next read will be the end of the stream. Check out this post: Why is iostream::eof inside a loop condition considered wrong?
To separate, you can check the first char of the line is whether within ['0', '9'] or not.
Like this:
while( getline(myfile, line) )
{
if (line[0]>='0' && line[0]<='9')
{
// start with a number (do case b)
}
else
{
// other (do case a)
}
}

cin.eof() functionality

I understand that cin.eof() tests the stream format. And while giving input, end of character is not reached when there is wrong in the input. I tested this on my MSV C++ 2010 and am not understanding the strange results. No matter what I give the input, I am getting Format Error message that is present in the program.
#include <iostream>
using namespace std;
int main()
{
int i;
cin>> i;
if(!cin.eof())
{
cout<< "\n Format Error \n";
}
else
{
cout<< "\n Correct Input \n";
}
getchar();
return 0;
}
Results I expected:
Values for i =
10 => Correct Input but the output is Format Error
12a => Format Error
Could someone explain where I am going wrong. Thanks.
std::cin.eof() tests for end-of-file (hence eof), not for errors. For error checking use !std::cin.good(), the built-in conversion operator (if(std::cin)) or the boolean negation operator (if(!std::cin)).
Use a direct test of the status of the stream with:
while (cin >> i)
{
...
}
For an input stream to enter the EOF state you have to actually make an attempt to read past the end of stream. I.e. it is not enough to reach the end-of-stream location in the stream, it is necessary to actually try to read a character past the end. This attempt will result in EOF state being activated, which in turn will make cin.eof() return true.
However, in your case you are not only not doing that, you (most likely) are not even reaching the end of stream. If you input your 10 from the keyboard, you probably finished the input by pressing the [Enter] key. This resulted in a new-line character being added to the input stream. So, what you are actually parsing with >> operator in this case is actually a 10\n sequence. Since you requested an int value from the stream, it only reads the numerical characters from the stream, i.e. it reads 1 and 0, but it stops at \n. That \n remains in the stream. You never read it. So, obviously, your code never reaches the end-of-file position in the stream. You have to reason to expect cin.eof() to become true in such case.
#include <iostream>
int main() {
using namespace std;
int i;
if (cin >> i) {
cout << "Extracted an int, but it is unknown if more input exists.\n";
char c;
if (cin.get(c)) { // Or: cin >> c, depending on how you want to handle whitespace.
cin.putback(c);
cout << "More input exists.\n";
if (c == '\n') { // Doesn't work if you use cin >> c above.
cout << "But this was at the end of this line.\n";
}
}
else {
cout << "No more input exists.\n";
}
}
else {
cout << "Format error.\n";
}
return 0;
}
Also see Testing stream.good() or !stream.eof() reads last line twice.
Sample session with the above program, note that input lines are marked with comments not present in the actual output:
$ your-program
12 # input
Extracted an int, but it is unknown if more input exists.
More input exists.
But this was at the end of this line.
$ your-program
12a # input
Extracted an int, but it is unknown if more input exists.
More input exists.
$ echo -n 12 | your-program
Extracted an int, but it is unknown if more input exists.
No more input exists.
$ your-program
a # input
Format error.
Assuming your input is line based, I suggest that you read the whole line using std::getline(). Once you have the line, you can analyse it and decide whether it contains correct or wrong input. Put the line into std::istringstream and do something like the following:
Edit: Changed !! iss to static_cast<bool>(iss) for compatibility with C++0x.
std::istringstream iss (line);
char ch;
long lval;
// read the input
iss >> lval;
// result variable will contain true if the input was correct and false otherwise
result
// check that we have read a number of at least one digit length
= static_cast<bool>(iss)
// check that we cannot read anything beyond the value read above
&& ! (iss >> ch);
Adding to the previous answer:
After reading your input (like 10), you are not at end-of-file, as you can easily type some more. How is the system to know that you will not?
When reading your second input (12a), it correctly reads all the digits that can be part of an integer. The letter 'a' cannot, so it is left for some possible later input. For example, you can read all parts of 12a with this code
int i;
char c;
cin >> i >> c;
cin.eof() test if the stream has reached end of file which happens if you type something like Ctrl+C (on Windows), or if input has been redirected to a file etc.
To test if the input contains an integer and nothing but an integer, you can get input first into a string and then convert that with a stringstream. A stringstream indeed reaches eof if there's no more to be extracted from it.
#include <iostream>
#include <sstream>
#include <string>
int main() {
using namespace std;
int i;
string input;
cin >> input; //or getline(cin, input)
stringstream ss(input);
if (ss >> i && ss.eof()) { //if conversion succeeds and there's no more to get
cout<< "\n Correct Input \n";
}
else {
cout<< "\n Format Error \n";
}
return 0;
}