0

I have a file named 1.txt, it contains 3 lines, each line is stored in an object of class entry as follows:

1* 10/12/2020 5:30 a 11:15 p 0 0 0 0 -----
2* 11/12/2020 3:45 a 5:46 a 0 0 0 0 -----
3* 12/12/2020 5:46 a 4:56 p 34.6 0 0 0 blah

and I'm reading from this file line by line into Entry e, and storing each entry into std::vector<Enrty>records like this:

void read_records(std::ifstream file, Entry e, std::vector<Entry>&records)
{
    std::string line;
        std::cout << "READING TEXT FILE CONTENTS..." << std::endl;
        while (file)
        {
            getline(file, line);
            e.read_text(tokenize(line)); // tokenize tokenizes line to tokens and e.read_text stores data from that line into e
            records.push_back(e);
            e.reset(); // this resets e back to original state
        }
}

when I display records after calling this function it gives me an extra Entry in records like so, The contents in std::<Entry>records are :

1* 10/12/2020 5:30 a 11:15 p 0 0 0 0 -----
2* 11/12/2020 3:45 a 5:46 a 0 0 0 0 -----
3* 12/12/2020 5:46 a 4:56 p 34.6 0 0 0 blah
3* 12/12/2020 5:46 a 4:56 p 34.6 0 0 0 blah   // I'm getting this extra entry in records when the file only contains 3 entries.

Please explain why this is happening and now to fix this in visual studio C++.

1 Answers1

3

I think the problem here might root from the while statement - this will add an extra iteration from what you expect because this condition is only false after you've gone past the end of the file.

while(file) {
// ...
}

getline reads a whole line at a time, and since EOF is not a line you avoid the unwanted extra iteration. This is the correct way to ingest a file stream in this use case:

#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
#include <vector>

int main() {
  std::vector<std::string> records;
  std::ifstream infile("thefile.txt");
  std::string line;
  while (std::getline(infile, line)) {
    records.push_back(line);
  }
  for (std::string e : records) {
    std::cout << e << std::endl;
  }
}
Ayushya
  • 336
  • 1
  • 8
  • This seems to have fixed the probem, But can you elaborate more? Like why is `while (std::getline(infile, line))` better than `while(file)`? Shouldn't `while (std::getline(infile, line))` work the same way as `while(file)`? – Pratap Biswakarma Dec 11 '20 at 02:32
  • 1
    @PratapBiswakarma -- the difference is that with `while (file)`, when the `getline` call fails because it has reached the end of the input, the code in the rest of the loop body gets executed; it's only after that is done that the test in `while (file)` gets done. By testing the result of the call to `getline`, when the input ends, the code leaves the loop immediately. – Pete Becker Dec 11 '20 at 14:35
  • @PeteBecker Understood! Thank you! Can you explain how this method would be if I'm reading records from a binary file? – Pratap Biswakarma Dec 12 '20 at 01:08
  • I mean in a binary file where we just write the binary data and no formatting like space or newline etc. – Pratap Biswakarma Dec 12 '20 at 01:40