Why input stream object fails after reading file to the end? - c++

Here is the code .
It is giving the EXACT output as shown below means it is reading the file.
But it is also showing fails as you can see it means fin.fails() is true.
I want to know why this is true although i am successful in reading the file.
#include<fstream>
#include<iostream>
using namespace std;
int main()
{ ifstream fin;
fin.open("pro.txt");
char ch;
int data;
while(!fin.eof())//!(fin >> ch).eof()
{
fin.get(ch);
cout<<ch;
if(fin.fail()) {
cout<<"fails";
break;
}
}
fin.clear();
fin.seekg(0);
int pos=(int)fin.tellg();
cout<<"\n this is :"<<pos;
fin.close();
return 0;
}
Output is :
this is my name
fails
this is 0
Contents of pro.txt:
this is my name
Don't know why this is happening!

Still can't find why the fin.fails() is true because i think no one willing to
But i figured out to read white spaces and file without making fin.fails() =true .
just replace the while(!fin.eof()) with while(fin.get(ch)) and remove the fin.get(ch) present in while body -> this was the reason why my output was skipping one character for each read.. this i had mentioned in the comments.

The problem is the following: Reading the last character in your file with get will not set the eofbit, so the call to fin.eof() in your while condition still returns false after you read the last character of the file inside the loop body. Then during the iteration following the read of the last character you try to read another character inside the loop body, even though there is no character to read anymore. This will set the eofbit and the failbit as per specification of get.
TL;DR: Reading over the end of a file is supposed to set the failbit.

Related

Reading from a file without skipping whitespaces

I'm trying to make a code which would change one given word from a file, and change it into another one. The program works in a way that it copies word by word, if it's normal word it just writes it into the output file, and if it's the one i need to change it writes the one i need to change to. However, I've enountered a problem. Program is not putting whitespaces where they are in the input file. I don't know the solution to this problem, and I have no idea if I can use noskipws since I wouldn't know where the file ends.
Please keep in mind I'm a complete newbie and I have no idea how things work. I don't know if the tags are visible enough, so I will mention again that I use C++
Since each reading of word is ended with either a whitespace or end of file, you could simply check whether the thing which stop your reading is end of file, or otherwise a whitespace:
if ( reached the end of file ) {
// What I have encountered is end of file
// My job is done
} else {
// What I have encountered is a whitespace
// I need to output a whitespace and back to work
}
And the problem here is how to check the eof(end of file).
Since you are using ifstream, things will be quite simple.
When a ifstream reach the end of file (all the meaningful data have been read), the ifstream::eof() function will return true.
Let's assume the ifstream instance that you have is called input.
if ( input.eof() == true ) {
// What I have encountered is end of file
// My job is done
} else {
// What I have encountered is a whitespace
// I need to output a whitespace and back to work
}
PS : ifstream::good() will return false when it reaches the eof or an error occurs. Checking whether input.good() == false instead can be a better choice here.
First I would advise you not to read and write in the same file (at least not during reading) because it will make your program much more difficult to write/read.
Second if you want to read all whitespaces easiest is to read whole line with getline().
Program that you can use for modifying words from one file to another could look something like following:
void read_file()
{
ifstream file_read;
ofstream file_write;
// File from which you read some text.
file_read.open ("read.txt");
// File in which you will save modified text.
file_write.open ("write.txt");
string line;
// Word that you look for to modify.
string word_to_modify = "something";
string word_new = "something_new";
// You need to look in every line from input file.
// getLine() goes from beginning of the file to the end.
while ( getline (file_read,line) ) {
unsigned index = line.find(word_to_modify);
// If there are one or more occurrence of target word.
while (index < line.length()) {
line.replace(index, word_to_modify.length(), word_new);
index = line.find(word_to_modify, index + word_new.length());
}
cout << line << '\n';
file_write << line + '\n';
}
file_read.close();
file_write.close();
}

How Do I use input to pass a string into a char array from a Text File

Hey I know I can just use a string to read from a text file. However I need to use a char array. Like If I was using a string I would do this
while (!input.eof()){
input >> s;
}
I am unsure how I would go about this if I don't know the length of the string. I know I can use getLine, but I'll prefer to use input.
I'm thinking that maybe I can use a loop to check until it reaches "\0"?
Anyway I have a feeling this question has been asked before, but if it has I can't find it. So sorry if that is the case.
You can consider istream::getline. Note that it can be use for C++ string and it must have a length limit for C string.
I think you should avoid check eof directly in while condition. It only returns true it reach end-of-file. So if you have multiple line, you read it, then do some calculate, the consequence can be unexpected when it reach the end-of-file right at reading step. So the check of EOF should be placed right after reading from stream like my example.
int main()
{
ifstream input("filename.txt");
const int MAX = 10000;
char characters[MAX];
while (true) {
input.getline(characters, MAX - 1, '\n');
if (input.eof())
break;
}
}

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))

Error reading and printing a text file with C++

I have a bug with my code (the code at the end of the question). The purpose of my C++ executable is to read a file that contains numbers, copy it in a std::vector and
then just print the contents in the stdout? Where is the problem? (atoi?)
I have a simple text file that contains the following numbers (each line has one number)
mini01:algorithms ios$ cat numbers.txt
1
2
3
4
5
When I execute the program I receive one more line:
mini01:algorithms ios$ ./a.out
1
2
3
4
5
0
Why I get the 6th line in the stdout?
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
void algorithm(std::vector<int>& v) {
for(int i=0; i < v.size(); i++) {
cout << v[i] << endl;
}
}
int main(int argc, char **argv) {
string line;
std::vector<int> vector1;
ifstream myfile("numbers.txt");
if ( myfile.is_open()) {
while( myfile.good() )
{
getline(myfile, line);
vector1.push_back(atoi(line.c_str()));
}
myfile.close();
}
else {
cout << "Unable to open file" << endl;
}
algorithm(vector1);
return 0;
}
You should not use while (myfile.good()), as it will loop once to many.
Instead use
while (getline(...))
The reason you can't use the flags to check for looping, is that they don't get set until after an input/output operation notices the problem (error or end-of-file).
Don't use good() as the condition of your extraction loop. It does not accurately indicate whether the next read will succeed or not. Move your call to getline into the condition:
while(getline(myfile, line))
{
vector1.push_back(atoi(line.c_str()));
}
The reason it is failing in this particular case is because text files typically have an \n at the end of the file (that is not shown by text editors). When the last line is read, this \n is extracted from the stream. Yes, that may be the very last character in the file, but getline doesn't care to look any further than the \n it has extracted. It's done. It does not set the EOF flag or do anything else to cause good() to return false.
So at the next iteration, good() is still true, the loop continues and getline attempts to extract from the file. However, now there's nothing left to extract and you just get line set to an empty string. This then gets converted to an int and pushed into the vector1, giving you the extra value.
In fact, the only robust way to check if there is a problem with extraction is to check the stream's status bits after extracting. The easiest way to do this is to make the extraction itself the condition.
You read one too many lines, since the condition while is false AFTER you had a "bad read".
Welcome to the wonderful world of C++. Before we go to the bug first, I would advise you to drop the std:: namespace resolution before defining or declaring a vector as you already have
using namespace::std;
A second advise would be to use the pre increment operator ++i instead of i++ wherever feasible. You can see more details on that here.
Coming to your problem in itself, the issue is an empty new line being read at the end of file. A simple way to avoid this would be to check the length of line before using it.
getline(myfile, line);
if (line.size()) {
vector1.push_back(atoi(line.c_str()));
}
This would enable your program now to read a file interspersed with empty lines. To be further foolproof you can check the line read for presence of any non numeric characters before using atoi on it. However the best solution as mentioned would be use to read the line read to the loop evaluation.

Function End of file loops extra loop ? 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.
am trying to read characters from file but when I use end of file function it loops more than the number of character inside the file by 1 .. but I don't know why ?
#include <iostream>
#include <fstream>
int main()
{
ifstream file;
char ch1;
file.open("c:\\Downloads\\test.txt" , ios::in);
int i=0;
while(!file.eof())
{ i++;
file>>ch1;
cout<<ch1<<endl;
}
cout <<i<<endl;
file.close();
return 0;
}
file contains
[]
output : [ ] ] 3
Well, when you've read the last character in the file file.eof() is still false, because the stream doesn't yet know that it's reached the end. Only after you attempt to read the already nonexistent character is eof set to true. You should probably do this
char ch;
while(file >> ch)
{
...
}
The reason is because just because you haven't hit the end of the file yet, doesn't mean the next read is going to succeed. Because you are reading characters, the EOF will only be set when you actually attempt to read after the last character.
In fact, even when you are reading strings, integers or other similar things out of a file there is a similar problem. At the end of many text files is an extra \n with no text after it. So when the last line is read, there is still a \n in the stream but EOF has not been set. You then proceed to read the next line which is not there whatever you are extracting into is left with the same contents as before. This results in what appears to be a duplicate reading.