0

I am currently making a program that reads a CSV file with information about films from 2015, and then makes film objects based on that information, and then adds those films to a binary search tree.

The problem I am facing is it will only read three lines of the CSV file. Below is the method I am using to read the file.

void FilmDatabase::createDatabase (void)
{
      string InputFile = "films2015.csv";

      string inputString = "";
      ifstream inFile(InputFile.c_str());

      int rank= 0;
      string filmTitle = "";
      string studio = "";
      double totalGross = 0;
      int totalTheaters = 0;
      double openingGross = 0;
      int openingTheaters = 0;
      string openingDate = "";

      string token = "";

      if(!inFile)
      {
         cout << "File not found" << endl;
      }
      else
      {
         while(!inFile.eof())
         {
            getline(inFile, inputString);
            istringstream iss1(inputString);

            getline(iss1, token, ',');            
            rank = atoi(token.c_str());

            getline(iss1, token, ',');            
            filmTitle = token;

            getline(iss1, token, ',');            
            studio = token;

            getline(iss1, token, ',');            
            totalGross = stod(token);

            getline(iss1, token, ',');            
            totalTheaters = atoi(token.c_str());

            getline(iss1, token, ',');            
            openingGross = stod(token);

            getline(iss1, token, ',');            
            openingTheaters = atoi(token.c_str());

            getline(iss1, token, ',');
            openingDate = token;

            Film film(rank, filmTitle, studio, totalGross, totalTheaters, openingGross, openingTheaters, openingDate);

            film.printFilm();

            filmDatabaseBST.add(film);
         }
         
         inFile.close();
      }    
}

The data for this program looks something like this

1,Star Wars: The Force Awakens,BV,916257964.00,4134,247966675.00,4134,12/18/15 2,Jurassic World,Uni.,652270625.00,4291,208806270.00,4274,6/12/15 3,Avengers: Age of Ultron,BV,459005868.00,4276,191271109.00,4276,5/1/15 4,Inside Out,BV,356461711.00,4158,90440272.00,3946,6/19/15 5,Furious 7,Uni.,353007020.00,4022,147187040.00,4004,4/3/15 6,Minions,Uni.,336045770.00,4311,115718405.00,4301,7/10/15 7,The Hunger Games: Mockingjay - Part 2,LGF,281392486.00,4175,102665981.00,4175,11/20/15

EJBrawler
  • 1
  • 1
  • First of all please read [Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-i-e-while-stream-eof-cons) Then learn how to use a *debugger* to step through your code statement by statement while monitoring variables and their values. Lastly, CSV files are *deceptively* simple, but have corner-cases which are far from trivial. I really recommend finding a library to help you read CSV files. – Some programmer dude Nov 21 '21 at 18:01
  • It would help if you could provide us with original input data, for example the first **4** lines of your original file: Because it's odd that the program stops at line 3. Are you aware that e.g. std::stod() throws an exception if the string->double conversion fails? That's the most likely reason. – Peter - Reinstate Monica Nov 21 '21 at 19:48

1 Answers1

0

There's a few things you can do differently. Some of them are just to avoid C-isms when doing C++.

 totalTheaters = atoi(token.c_str());

Do this instead:

 totalTheaters = std::stoi(token);

Next, most people will complain about something like this:

 Film film(rank, filmTitle, studio, totalGross, totalTheaters, openingGross, openingTheaters, openingDate);

That's an insane number of arguments, which makes it error prone. But both of these are style problems.

Your main loop can be:

while (getline(inFile, inputString)) {
    ...
}

And then at this point, I feel it's a mistake to use istringstream to parse your file. Instead, I would do something like this:

std::vector<string> parts;
size_t pos = 0;
size_t nextPos;
while ((nextPos = inputString.find(",", pos)) != string::npos) {
     parts.push_back(inputString.substr(pos, nextPos));
     pos = nextPos + 1;
}
parts(inputString.substr(pos);

At this point, the vector contains the portions of the line, delimited by commas, and you can do error handling.

Will this fix your problem? Perhaps not. But if your data is malformed, your code will throw exceptions. This code is less likely to do so.

Joseph Larson
  • 8,530
  • 1
  • 19
  • 36
  • 1
    "*I feel it's a mistake to use istringstream to parse your file*" - why? It is very common, and generally preferred, to use `istringstream` to parse line-based data. Using `istringstream` with `vector`, your example simplifies greatly, and is much more readable: `std::vector parts; while (getline(iss1, token, ',')) { parts.push_back(token); }` – Remy Lebeau Nov 21 '21 at 19:21
  • @RemyLebeau Error handling becomes harder unless you use a ton of try/catch. It also becomes significantly harder to accept alternate types of input -- such as t/f for booleans. Plus if you really want to properly handle CSV, you really should use a parser that is smart enough to understand quoted strings. – Joseph Larson Nov 22 '21 at 19:13
  • `try/catch` only applies to exceptions, and streams don't throw exceptions by default, you have to explicitly enable that. Parsing true/false is simple with `std::boolalpha`. But you are right about using a CSV parser. – Remy Lebeau Nov 22 '21 at 21:47