File handling not working with fstream after reaching eof? - c++

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.

Related

C++ file stream for reading/writing

I need to open a file for both reading/writing using fstream and read each character then write that character back to the file. for example i have this code.
fstream in("test.txt",ios::in | ios::out);
if(!in)
cout<<"error...";
else
{
char ch;
in.seekg(0,ios::end);
int end=in.tellg();//get the length
in.seekg(0);//get back to the start
for(int i=0;i<end;i++)
{
//in.seekg(in.tellg());//if i uncomment this the code will work
if(!in.get(ch).fail())//read a character
{
in.seekp(static_cast<int>(in.tellg())-1);//move the pointer back to the previously read position,so i could write on it
if(in.put(ch).fail())//write back,this also move position to the next character to be read/write
break;//break on error
}
}
}
I have a file named "test.txt" which contains "ABCD". As i understand it both put() and get() methods of the stream object move the file pointer forward(i see that by getting the return value of tellg() or tellp() functions after each get() or put() method call). My question is when i comment out the code that will seek the stream pointer to "where it is now"(in.seekg(in.tellg()), the code will result incorrect results. I don't understand why this is since tellg() is showing the correct position of the character to be read next.what is the purpose of explicitly seeking to it? I am using visual studio 2005.
The incorrect result is it writes to the file "ABBB" instead of "ABCD".
The output buffer has to be flushed when switching between write and read.
fstream in("test.txt",ios::in | ios::out);
if(!in)
cout<<"error...";
else
{
char ch;
in.seekg(0,ios::end);
int end=in.tellg();//get the length
in.seekg(0);//get back to the start
for(int i=0;i<end;i++)
{
if(!in.get(ch).fail())//read a character
{
in.seekp(static_cast<int>(in.tellg())-1);//move the pointer back to the previously read position,so i could write on it
if(in.put(ch).fail())//write back,this also move position to the next character to be read/write
break;//break on error
in.flush();
}
}
}

How to read and write in file with `fstream` simultaneously in c++?

I have the following code
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
int main(void) {
fstream ofile;
ofile.open("test.txt", ios::in | ios::out | ios::app);
for(string line; getline(ofile, line) ; ) {
cout << line << endl;
}
ofile << "stackexchnange" << endl;
ofile.close();
return 0;
}
test.txt contains
hello world!
stackoverflow
Above code outputs
hello world!
stackoverflow
And after running the code stackexchange is not appending at the end of test.txt. How to read and then write in file?
Nawaz' comment is correct. Your read loop iterates until the fstream::operator bool (of ofile) returns false. Therefore, after the loop, either failbit or badbit must have been set. failbit is set when loop tries to read for the final time but only EOF is left to read. This is completely OK, but you must reset the error state flag before trying to use the stream again.
// ...
ofile.clear();
ofile << "stackexchnange" << endl;
fstream has two positions : input and output.
In your case they both are set to the beginning of the file when you open it.
So you have 4 methods:
tellp // returns the output position indicator
seekp // sets the output position indicator
tellg // returns the input position indicator
seekg // sets the input position indicator
in your case you can use the following line to set output position to the end of the file
ofile.seekp(0, std::ios_base::end);
PS
i missed ios::app flag. mea culpa. comment of #Nawaz gives the right answer: after reading the whole file it is necessary to call
ofile.clear(); //cleanup error and eof flags

Writing out to a file in C++

Here is my code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string fname,lname;
double pincrease //pay increase percentage,pay;
ifstream infile;
ofstream outfile;
infile.open("C:\\Users\\Connor\\Desktop");
outfile.open("C:\\Users\\Connor\\Desktop");
while(!infile.eof())
{
infile>>lname>>fname>>pay>>pincrease;
pay = pay*(pay*pincrease);
outfile<<fname<<" "<<lname<<" "<<pay<<"\n";
cin.clear();
}
infile.close();
outfile.close();
}
And here are the contents of my infile:
Miller Andrew 65789.87 5
Green Sheila 75892.56 6
Sethi Amit 74900.50 6.1
The information is in the form of Last Name:First Name:Pay:Pay Increase Percentage.
The order swap of the first and last name and the exclusion of the pay percent increase when I write to the outfile is intentional.
I'm trying to read the contents of the infile, modify them, and then write it to an outfile.
However when I execute the code I start what I'm pretty sure is an infinite loop but I'm not sure how to fix it.
Neither of these statements likely open files:
infile.open("C:\\Users\\Connor\\Desktop");
outfile.open("C:\\Users\\Connor\\Desktop");
Rather, they attempt (and likely fail) to open your Desktop folder. Rather, you likely wanted something more like:
infile.open("C:\\Users\\Connor\\Desktop\\infile");
outfile.open("C:\\Users\\Connor\\Desktop\\outfile");
Of course, infile and outfile at the end there should be replaced with actual filenames.
You can test whether your file opens succeeded by checking infile.is_open() and outfile.is_open(). You might add explicit if statements to test this:
if (!infile.is_open())
// report/handle that you couldn't open input file
if (!outfile.is_open())
// report/handle that you couldn't open output file
For your main loop, you shouldn't be testing eof as you do. Rather, use something like this:
while(infile>>lname>>fname>>pay>>pincrease)
{
pay = pay*(pay*pincrease);
outfile<<fname<<" "<<lname<<" "<<pay<<"\n";
cin.clear();
}
Testing for EOF the way you were will try to read one extra record beyond end of file.
The EOF flag only gets set after a failed read attempt. Therefore you should always test for EOF after trying to read.
The standard ifstream is set up in such a way that a typical ifstream input operation (ie. infile >> item) will return a reference to an ifstream object. That's how you can do things like infile >> item1 >> item2 >> item3.
When you place that in the context of a loop control (as above), ifstream has the appropriate operator overloads that cause it to tell while whether to keep looping or not based on whether the reads succeeded.
Others have explained that overload magic well enough elsewhere. More info on the loop termination magic here: Why istream object can be used as a bool expression?
Replace this
infile.open("C:\\Users\\Connor\\Desktop");
outfile.open("C:\\Users\\Connor\\Desktop");
with this
infile.open("C:\\Users\\Connor\\infile.txt");
outfile.open("C:\\Users\\Connor\\outfile.txt");
The code you have posted will not compile for two reasons. One, The variable pay has not been declared and two, you have commented out the termination of the following code.
double pincrease //pay increase percentage,pay;
Try the below code. Hope it helps
int main()
{
string fname,lname;
double pincrease; //pay increase percentage,pay;
double pay;
ifstream infile;
ofstream outfile;
infile.open("C:\\Users\\Connor\\infile.txt");
outfile.open("C:\\Users\\Connor\\outfile.txt");
while(!infile.eof())
{
infile>>lname>>fname>>pay>>pincrease;
pay = pay*(pay*pincrease);
outfile<<std::setprecision(2)<<std::showpoint << std::fixed;;
outfile<<fname<<" "<<lname<<" "<<pay<<"\n";
cin.clear();
}
infile.close();
outfile.close();
}

C++ Binary File method is removing content from the file?

I have an assignment where I am writing input on various things (in the form of structs) and then writing to a binary file. I have to be able to both read and write to the file while the program is open. One of the methods needs to print out all of the clients in the binary file. It seems to be working, except whenever I call that method, it seems to erase the contents of the file and prevent more from being written to it. Here's the applicable snippets:
fstream binaryFile;
binaryFile.open("HomeBuyer", ios::in | ios::app | ios::binary);
The same file is supposed to be usable between times you run the program, so I should open it with ios::app, correct?
Here's the method to add an entry:
void addClient(fstream &binaryFile) {
HomeBuyer newClient; //Struct the data is stored in
// -- Snip -- Just some input statements to get the client details //
binaryFile.seekp(0L, ios::end); //This should sent the write position to the
//end of the file, correct?
binaryFile.write(reinterpret_cast<char *>(&newClient), sizeof(newClient));
cout << "The records have been saved." << endl << endl;
}
And now the method to print all the entries:
void displayAllClients(fstream &binaryFile) {
HomeBuyer printAll;
binaryFile.seekg(0L, ios::beg);
binaryFile.read(reinterpret_cast<char *>(&printAll),sizeof(printAll));
while(!binaryFile.eof()) { //Print all the entries while not at end of file
if(!printAll.deleted) {
// -- Snip -- Just some code to output, this works fine //
}
//Read the next entry
binaryFile.read(reinterpret_cast<char *>(&printAll),sizeof(printAll));
}
cout << "That's all of them!" << endl << endl;
}
If I step through the program, I can input as many clients as I want, and it will output them all the first time I call displayAllClients(). But as soon as I call displayAllClients() once, it seems to clear out the binary file, and any further attempts at displaying clients gives me no results.
Am I using seekp and seekg incorrectly?
From what I understand, this should set my write position to the end of the file:
binaryFile.seekp(0L, ios::end);
And this should set my read position to the beginning:
binaryFile.seekg(0L, ios::beg);
Thanks!
Pasting comment in as this resolved the issue.
You need to call binaryFile.clear() before seekp() and seekg() if EOF is set, otherwise they won't work.
This is the documentation for ios::app
ios::app
All output operations are performed at the end of the file, appending the
content to the current content of the file. This flag can only be used in
streams open for output-only operations.
Since this is homework, I'll let you draw your own conclusions.

getline() reads an extra line

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.