Home > Mobile >  Read different data types from .csv file and store them into a struct array
Read different data types from .csv file and store them into a struct array

Time:02-05

I need to read a .csv file, put the information into a struct, then insert the struct into a binary file. Each column means:

(int)Year; (int)Rank; (char*)University's Name; (float)Score; (char*)City; (char*)Country 

My .csv file looks like:

2018,1,Harvard University,97.7,Cambridge,United States
2018,2,University of Cambridge,94.6,Cambridge,United Kingdom
2018,3,University of Oxford,94.6,Oxford,United Kingdom
2018,4,Massachusetts Institute of Technology (MIT),92.5,Cambridge,United States
2018,5,Johns Hopkins University,92.1,Baltimore,United States

As you can see, it contains the five best universities in the world.

The issue is my code can't read properly neither the integers (perhaps due to commas in the file) nor the char[30].

struct Data
{
  int year;
  int rank;
  char name[30];
  float score;
  char city[30];
  char country[30];
};


`Data *universitie = new Data [5];
ifstream read ( "myFile.csv" );
int i = 0;

while ( !read.eof() ) {
read >> universitie[i].year;
read >> universitie[i].rank;
read.getline (universitie[i].name, 30, ','); //here a segmentation fault happened
read >> universitie[i].score;
read.getline (universitie[i].city, 30, ','); //here a segmentation fault happened
read.getline (universitie[i].country, 30, '\n'); //here a segmentation fault happened
i  ;
}
read.close ();

I'm actually using char[30] for name, city and country instead of string because then I'll write this struct array into a binary file.

How can I properly read the integers until the comma? How to read a character array from a file using getline() with delimeters like ','?

This is for my Computer Science course's task.

CodePudding user response:

The usual technique with CSV files is to model a record with a class, then overload operator>> to input a record:

struct Record
{
  int year;
  int rank;
  std::string name;
  double      score;
  std::string city;
  std::string country;
  friend std::istream& operator>>(std::istream& input, Record& r);
};

std::istream& operator>>(std::istream& input, Record& r)
{
  char comma;
  input >> r.year;
  input >> comma;
  input >> r.rank;
  input >> comma;
  std::getline(input, r.name, ',');
  input >> r.score;
  std::getline(input, r.city, ',');
  std::getline(input, r.country, '\n');
  return input;
}

A use case for the above could look like:

std::vector<Record> database;
ifstream data_file ( "myFile.csv" );
Record r;
while (data_file >> r)
{
  database.push_back(r);
}

Note: I have changed your char[] to std::string for easier handling. Also, I changed the while loop condition.

CodePudding user response:

//Open the file

Data *universitie = new Data [5];

int i = 0;
std::string line;
while(std::getline(file, line))
{
  std::stringstream ss;
  ss << line;
    
  ss >> universitie[i].year;
  ss.ignore();
  ss >> universitie[i].rank;
  ss.ignore();
  ss >> universitie[i].name;
  ss.ignore();
  ss >> universitie[i].score;
  ss.ignore();
  ss >> universitie[i].city;
  ss.ignore();
  ss >> universitie[i].country;
  
  i  ;
}

This is a solution with std::stringstream. The ignore() function is used to skip the ',' between the entries. Also in my opinion is better to use the C std::string class instead of char[30]. If at some point you need c string then you can use the c_str() function.

  • Related