File Reading Question

B

Brian Ward

First: sorry as a relative newbie for previously not including code.
My question:
Reading C++ books I almost always find programs such as the one below
give the following type of code for reading a file :

//********* BUM CODE *************************************
infile.open ("test.dat" , ios::in);

while (!infile.eof())
{
infile.read ((char *)&dog, sizeof (dog)); // read from file
cout << "Dog Name = " << dog.name << endl;
cout << "Dog age = " << dog.age << endl;
cout << "Dog weight = " << dog.weight << endl;
}
infile.close();
//******************************************************************
If you use this you find that the last record to be read is always
displayed twice!
Nowhere in the books can I find a mention, nor a solution to this.
My solution .. and I am always looking for the simplest to understand ..
is to use the 'read-ahead' technique to read the file

//***** READ AHEAD METHOD ****************************
infile.open ("test.txt" , ios::in);

infile.read ((char *)&dog, sizeof (dog)); // read ahead first record

while (!infile.eof())
{
cout << "Dog Name = " << dog.name << endl;
cout << "Dog age = " << dog.age << endl;
cout << "Dog weight = " << dog.weight << endl;
infile.read ((char *) &dog, sizeof (dog)); // read next record
}
infile.close();
//***********************************
This appears to work .. but as I have not seen this used anywhere I
wondered if there is anything wrong with it as a method?
Is there a better way?

//****** FULL BUM PROGRAM ****************************
#include <fstream>
#include <cstdlib>
#include <ctype.h> // needed for toupper()
#include <string>

using namespace std;

void StoreFileData(fstream& outfile);
void RetrieveFileData(fstream& infile);

class doggie // used basically as a structure
{
public:
char name[20] ;
int age;
float weight ;
};
//***********************************
int main()
{
fstream f;

StoreFileData(f);
RetrieveFileData(f);

system("PAUSE");
return 0;
}
//************************************
void StoreFileData(fstream& outfile)
{
doggie dog ;
char answer = 'Y';

outfile.open ("test.txt" , ios::eek:ut);

do
{
cout << "Enter dog name :";
cin >> dog.name;

cout << "What is " << dog.name << "\'s age : " ;
cin >> dog.age;
cout << "What is " << dog.name << "\'s weight : " ;
cin >> dog.weight;
outfile.write ((char *)&dog, sizeof (dog));
cout << "\nAny more dogs (y/n)?: ";
cin >> answer ;
answer = toupper (answer);
}
while (answer != 'N');
outfile.close();
}
//***********************************************
void RetrieveFileData(fstream& infile)
{
doggie dog ;

cout << "\nReading the file back now " << endl;

infile.open ("test.txt" , ios::in);

while (!infile.eof())
{
infile.read ((char *)&dog, sizeof (dog)); // read record

cout << "Dog Name = " << dog.name << endl;
cout << "Dog age = " << dog.age << endl;
cout << "Dog weight = " << dog.weight << endl;
}
infile.close();
}
//***********************************
 
R

Rolf Magnus

Brian said:
First: sorry as a relative newbie for previously not including code.
My question:
Reading C++ books I almost always find programs such as the one below
give the following type of code for reading a file :

//********* BUM CODE *************************************
infile.open ("test.dat" , ios::in);

while (!infile.eof())
{
infile.read ((char *)&dog, sizeof (dog)); // read from
file cout << "Dog Name = " << dog.name << endl;
cout << "Dog age = " << dog.age << endl;
cout << "Dog weight = " << dog.weight << endl;
}
infile.close();
//******************************************************************
If you use this you find that the last record to be read is always
displayed twice!

That's because that usage is wrong! eof() doesn't return true until
_after_ you tried to read past the end of the file. So when your last
read operation reached the end, eof() will still be false, and the loop
is executed once more, but there is no data left. The next read
operation fails, your stream goes into eof() state, but the additional
loop iteration has already been done before the loop ends.
Nowhere in the books can I find a mention, nor a solution to this.
My solution .. and I am always looking for the simplest to understand
.. is to use the 'read-ahead' technique to read the file

//***** READ AHEAD METHOD ****************************
infile.open ("test.txt" , ios::in);

infile.read ((char *)&dog, sizeof (dog)); // read ahead first
record

while (!infile.eof())
{
cout << "Dog Name = " << dog.name << endl;
cout << "Dog age = " << dog.age << endl;
cout << "Dog weight = " << dog.weight << endl;
infile.read ((char *) &dog, sizeof (dog)); // read next
record
}
infile.close();
//***********************************
This appears to work .. but as I have not seen this used anywhere I
wondered if there is anything wrong with it as a method?
Is there a better way?

Try:

infile.open ("test.dat" , ios::in);

while (infile.read ((char *)&dog, sizeof (dog)))
{
cout << "Dog Name = " << dog.name << endl;
cout << "Dog age = " << dog.age << endl;
cout << "Dog weight = " << dog.weight << endl;
}
infile.close();

if (infile.eof())
; // ok, end of file reached
else
std::cout << "error\n"; // some read error happened


That's the typical outline of reading a file in C++.
 
D

David Harmon

Reading C++ books I almost always find programs such as the one below
give the following type of code for reading a file :
while (!infile.eof())

Please post the author, title, and page# of the offending book(s)!

This issue is covered in Marshall Cline's C++ FAQ. See topic "[15.4]
Why does my input seem to process past the end of file?" It is always
good to check the FAQ before posting. You can get the FAQ at:
http://www.parashift.com/c++-faq-lite/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,159
Messages
2,570,879
Members
47,417
Latest member
DarrenGaun

Latest Threads

Top