Why fstream prints out last record of a file - c++

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.

Related

Whats the optimal conditional for counting number of lines in text file?

I've got the following code where I'm trying to count the number of lines in an input file, and I've tried several different ways of implementing it, but no luck.
int checkData(string File)
{
string temp;
int linecount = 0;
ifstream input(File);
input.open(File);
while ()
{
getline(input,temp);
linecount++;
temp.clear();
}
return linecount;
}
So far, I've tried:
while(!input.eof())
{
...
}
and
while(getline(input,temp).good())
{
...
}
The first doesnt break the loop, and I'm not quite sure why. (I'm fairly sure) that getline has a built in stream buffer, so it should automatically read the net line everytime I pull in a line and throw it back out, but no dice. For the second, the loop doesn't execute at all, which still doesn't make sense to me (that says that the first line of file isn't good input?).
The test file I'm using is:
this is a test this Cake
this is a test this Cake
this is a test this Cake
this is a test this Cake
So linecount should be returning as 4 when executing correctly. Before I execute this, I've already checked to make sure the file is opening correctly.
output
int number_of_lines = 0;
string line;
ifstream myfile("textexample.txt");
while (std::getline(myfile, line))
++number_of_lines;
Hope it helps.

C++ Read in file with only numbers (doubles)

I'm trying to read in a file that should contain only numbers in it. I can successfully read in the entire file if it meets that criteria, but if it so happened to have a letter in it, I need to return false with an error statement.
The problem is I'm finding it hard for my program to error when it finds this character. It can find it no problem, but when it does, it decides to just skip over it.
My code to read in the file and attempt to read in only numbers:
bool compute::Read (ifstream& stream)
{
double value;
string line;
int lineNumber = 1;
if (stream)
{
while (getline(stream, line))
{
lineNumber++;
istringstream strStream(line);
while (strStream >> value)
{
cout << value << endl;
}
}
}
return true;
}
The input file which I use for this is
70.5 61.2 A8 10.2
2
Notice that there is a non-number character in my input file. It should fail and return false at that point.
Currently, all it does is once it hits the "A", it simply returns to the next line, continuing the getline while loop.
Any help with this would be much appreciated.
The stringstream does catch those errors, but you're doing nothing to stop the enclosing loop from continuing when an error is found. You need to tailor your main loop so that it stops when the stringstream finds an error, which you can't do if the stringstream is being reconstructed on each iteration. You should create a for() loop instead and construct the stringstream in the declaration part. And the condition to the loop should be "as long as the stringstream and stream do not catch an error". For example:
for (std::istringstream iss; iss && std::getline(stream, line);)
{
iss.clear();
iss.str(line);
while (iss >> value)
{
std::cout << value << '\n';
}
}
Futhermore, it doesn't look like you need to use std::getline() or std::istringstream if you just want to print each value. Just do:
while (stream >> value) {
std::cout << value << '\n';
}
The above will stop when it finds an invalid character for a double.
You need the code to stop streaming but return false if it hasn't yet reached the end of the "input".
One way, possibly not the most efficient but still one way, to do that is parse a word at a time.
If you read first into a std::string and if it works (so the string is not empty) create an istringstream from that string, or reuse an existing one, and try streaming that into a double value.
If that fails, you have an invalid character.
Of course you can read a line at a time from the file, then split that into words, so that you can output a meaningful error message showing what line the bad text was found.
The issue of reading straight into doubles is that the stream will fail when it reaches end of file.
However it is possible to workaround that too because the reason for failing has an error status which you can check, i.e. you can check if it eofbit is set. Although the f in eofbit stands for "file" it applies to any stream not just files.
Although this method may sound better than reading words into a string first, I prefer that method in normal circumstances because you want to be able to report the error so you'll want to print in the error what was read.

Cannot read from file

I'm having a problem reading an integer from a file. As for my knowledge it should work. Can you tell me what have I done wrong here?
int fileCount = 0;
ifstream listFileStream ( fileName );
if ( listFileStream.is_open() ) {
listFileStream >> fileCount;
cout << fileCount;
}
It only prints 0 even though the first line of the file is 28.
You should always check that you read attempt was successful:
if (listFileStream >> fileCount) {
process(fileCount);
}
If the read isn't successful you can try to recover from it or report an error. Here is one way you might try to recover: restore the stream to good state and ignore the first character:
listFileStream.clear();
listFileStream.ignore();
Without restoring the stream to a good state all input attempts would be ignored. Once the offending character is removed you would retry the read.

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.

getline and file handling

I want to read the first lines of 2 separate files and then compare them...the following is the code i use but it gives me "istream to string error". do i need to use a while condition to start reading the files first?
ifstream data_real(filename.c_str()); /*input streams to check if the flight info
are the same*/
ifstream data_test("output_check.txt");
string read1, read2;
string first_line_input = getline(is,read1);
string first_line_output_test = getline(data_test,read2);
string test_string1, test_string2;
int num_lines_output_test, num_lines_input;
if((first_line_input.substr(0,3)==first_line_output_test.substr(0,3)))
{
while(!data_test.eof()) // count the number of lines for the output test file with the first flight info
{
getline(data_test,test_string1);
num_lines_output_test++;
}
while(getline(is,test_string2)) // count the number of lines for the output test file with the first flight info
{
if(test_string2.substr(0,3)!="ACM")
num_lines_input++;
else
break;
}
}
getline(istream, string) returns a reference to the istream, not a string.
So, comparing the first line of each file could be something like:
string read1, read2;
if !(getline(is,read1) && getline(data_test,read2)){
// Reading failed
// TODO: Handle and/or report error
}
else{
if(read1.substr(0,3) == read2.substr(0,3)){
//...
Also: Never use eof() as a termination condition for a stream reading loop. The idiomatic way to write it is:
while(getline(data_test,test_string1)) // count the number of lines for the output test file with the first flight info
{
num_lines_output_test++;
}
Try adding this helper function:
std::string next_line(std::istream& is) {
std::string result;
if (!std::getline(is, result)) {
throw std::ios::failure("Failed to read a required line");
}
return result;
}
Now you can use lines from the file the way you want (i.e. to initialize strings, rather than modify them):
string first_line_input = next_line(is);
string first_line_output_test = next_line(data_test);