getline() reads an extra line - c++

ifstream file("file.txt");
if(file.fail())
{
cout<<"Could not open the file";
exit(1);
}
else
{
while(file)
{
file.getline(line[l],80);
cout<<line[l++]<<"\n";
}
}
I am using a two dimensional character array to keep the text (more than one line) read from a file to count the number of lines and words in the file but the problem is that getline always reads an extra line.

Your code as I'm writing this:
ifstream file("file.txt");
if(file.fail())
{
cout<<"Could not open the file";
exit(1);
}
else
{
while(file)
{
file.getline(line[l],80);
cout<<line[l++]<<"\n";
}
}
The first time getline fails, you still increment the line counter and output the (non-existing) line.
Always check for an error.
extra advice: use std::string from the <string> header, and use its getline function.
cheers & hth.

The problem is when you're at the end of the file the test on file will still succeed because you have not yet read past the end of file. So you need to test the return from getline() as well.
Since you need to test the return from getline() to see if it succeeded, you may as well put it right in the while loop:
while (file.getline(line[l], 80))
cout << line[l++] << "\n";
This way you don't need a separate test on file and getline().

This will solve your problem:
ifstream file("file.txt");
if(!file.good())
{
cout<<"Could not open the file";
exit(1);
}
else
{
while(file)
{
file.getline(line[l],80);
if(!file.eof())
cout<<line[l++]<<"\n";
}
}
Its more robust

Does the file end with a newline? If it does, the EOF flag will not be triggered until one extra loop passes. For example, if the file is
abc\n
def\n
Then the loop will be run 3 times, the first time it will get abc, the second time it will get def and the third time it will get nothing. That's probably why you see an additional line.
Try checking the failbit on the stream AFTER the getline.

Only do the cout if file.good() is true. The extra line you're seeing comes from the last call to file.getline() which reads past the end of the file.

Related

Why fstream prints out last record of a file

why is it that the last record of a binary file is being printed out twice?
while( (inFile)
{
inFile.read(reinterpret_cast <char*> (&acc), sizeof(acc));
display(acc);
}
Because your code should read
while (inFile.read(reinterpret_cast<char*>(&acc), sizeof(acc))
{
display(acc);
}
Your version only tests for failure after you've printed the failed read. Or to put it another way while (infile) is not a test that the next read will succeed, it's a test that the last read succeeded.

File handling not working with fstream after reaching eof?

On your suggestion i have changed the code as you suggested but still problems are there when ios::out is replaced with ios::ate nothing is written in the file(Writing does not work). Is there any way to check that if the next bit is eof rather than reading it and then checking it? as suggested by you.And sometimes when i do file handling it shows the position of file pointer to be -1 what could that mean???
Code:
int main ()
{
char p[80];
fstream file("text1.txt",ios::out|ios::in); //if ios::ate is added here it results into infinite loop
cout<<"Starting position of the file is "<<file.tellg()<<endl;
getch();
if(file.is_open())
cout<<"file is open\n";
else
cout<<"file is not open\n";
getch();
file.seekp(0);
while(file>>p)
{
cout<<p<<endl;
}
file.clear();
cout<<"\nThe current position of the file pointer is "<<file.tellg()<<endl;
file.seekp(0);
if(file.eof())
cout<<"\n the eof\n";
while(file>>p)
{
cout<<p<<endl;
}
file.close();
return 0;
}
Output:
Starting position of the file is 0
file is open
Hello
man
how
are
you
The current position of the file pointer is 21
Hello
man
how
are
you
With this kind of reading from file reaching end-of-file causes setting both eof and failbit. Failbit is setted because creating your read loop with file.eof() condition doesn't indicate that next read will be the end of the stream. It just states that we didn't reach eof yet, so with:
while(file.eof())
{
file >> p;
}
It's possible that last read will be eof only, and we'll work with uninitialised data. IF this happens no characters will be extracted inside p and both eof and fail flags will be set.
When working with c++98 need to reset failbit to false by using:
file.clear();
To avoid bad readings situation you should extract characters from file inside while condition: while(file >> p). I recommend this or this questions on stack overflow.
So proper C++98 code should look like this:
while(file >> p)
{
std::count << p << std::endl;
}
file.clear();
file.seekp(0);
while(file >> p)
{
std::count << p << std::endl;
}
file.close();
I tested it couple of times on Visual Studio 2013 and it worked everytime.
Considering ios::ate mode:
ios::out, ios::in are modifiers that states how do we open file in question. If you want to read something from file you need to use ios::out flag, and for writing you need to use ios::in.
On the other hand ios::ate just tells compiler to open file and immediately go to the end of file. So if you substitute ios::out with ios::ate writing would be impossible, and program will rise failflag on file << "Hello...";.
And if you just want to append data, but read from the beginning of file you should use ios::app instead, because it tells to seek eof before each write.

How to read content of the file and save it to string type variable? Why there is empty space?

This is how I get the name of the file from the command line and open a file and save the content of the file line by line to a string. All the procedures works fine except three empty spaces at the beginning of the file. Is anyone can say why these empty spaces occurred and how can I ignore them?
string filename = "input.txt";
char *a=new char[filename.size()+1];
a[filename.size()]=0;
memcpy(a,filename.c_str(),filename.size());
ifstream fin(a);
if(!fin.good()){
cout<<" = File does not exist ->> No File for reading\n";
exit(1);
}
string s;
while(!fin.eof()){
string tmp;
getline(fin,tmp);
s.append(tmp);
if(s[s.size()-1] == '.')
{
//Do nothing
}
else
{
s.append(" ");
}
cout<<s<<endl;
The most probable cause is that your file is encoded in something else than ASCII. It contains a bunch of unprintable bytes and the string you on the screen is the result of your terminal interpreting those bytes. To confirm this, print the size of s after the reading is done. It should be larger than the number of characters you see on the screen.
Other issues:
string filename = "input.txt";
char *a=new char[filename.size()+1];
a[filename.size()]=0;
memcpy(a,filename.c_str(),filename.size());
ifstream fin(a);
is quite an overzealous way to go about it. Just write ifstream fin(a.c_str());, or simply ifstream fin(a); in C++11.
Next,
while(!fin.eof()){
is almost surely a bug. eof() does not tell if you the next read will succeed, only whether the last one reached eof or not. Using it this way will tipically result in last line seemingly being read twice.
Always, always, check for success of a read operation before you use the result. That's idiomatically done by putting getline in the loop condition: while (getline(fin, tmp))

getline() function in visual studio 2012 working differently, directly skipping to the last line

this is the first time i am using getline() and i think there is something wrong with it!
Here is my code:
ifstream file ("new2.csv");
string val;
while (file.good())
{
getline (file,val);
}
cout<<val;
and the output is always the last line of the csv file, no matter how many lines i have in the csv file.
my csv file is a simple Delimited file. like:
cat,dog,a,b,c,hello,world
monkey,flower,text,word
i think getline is supposed to read the first line of the csv file, but in this case, my output will be : monkey,flower,text,word
and this happens with any number of lines in the csv file.
i am unable to find out what may be doing this. please help me.
thanks.
Ofcourse it will only print the last line read from the file, because cout prints outside the loop and it prints the last line, after reading ALL lines finished.
You should write this instead:
ifstream file ("new2.csv");
string val;
while (file.good())
{
getline (file,val);
cout<< val << endl;
}
while (file.good())
{
getline (file,val);
}
cout<<val;
Your cout is outside the loop, so you'll only print the last line.

This loop is executing more iterations than is expected

I am having problems with the following code. What I expect is for the do-while loop to execute 4 times, once for each line of the text file it is reading in, but in reality is it executing five time, which is resulting in a segfault later in the program. What am I doing wrong here that's causing it to execute the extra iteration? I've tried replacing he do-while with a simple while loop but the result is the same.
int count = 0;
string devices[4];
string line;
ifstream DeviceList;
DeviceList.open("devices/device_list.txt");
do
{
getline(DeviceList, line);
devices[count] = line;
count ++;
} while(!DeviceList.eof());
device_list.txt contains the following:
WirelessAdaptor
GPU
CPU
Display
I think your loop should probably look more like this:
Edit: Added check to ignore empty lines
while (getline(DeviceList, line))
{
if (line.length() > 0)
{
devices[count] = line;
++count;
}
}
eof() doesn't return true until getline consumes the end. It doesn't do this until the getline call after reading the last line. You need to check if eof is true immediately after your getline call:
while(true)
{
getline(DeviceList, line);
if(DeviceList.eof())
break;
}
eof() won't return true until you attempt to read more data than there is left.
Above the line getline(DeviceList, line); insert cout << line.length() << endl; and tell us what happens.
Your text file probably contains a line feed after the last line, so getline reads an empty string before the loop actually ends.