How to read file using the overload operator>>? - c++

Suppose I have the following class with some private string:
class data{
public:
friend istream &operator>>(istream&, data&);
private:
string firstname;
string lastname;
string phonenum;
}
So, what is the right way to use the overload to read in my string from file. Here is my code. I had researched and seen people using getline. But when I use getline for my private data, it print out the whole different string.
istream &operator>>(istream &in, data &r)
{
// write this to read data object data
in.ignore();
in >> r.firstname;
in >> r.lastname;
in >> r.phonenum;
return in;
}
int main(){
ifstream inFile;
inFile.open("list1.txt"); // open file.txt
string line;
vector<data> A;
data din;
while (inFile >> din){
A.push_back(din);
cout << din << endl; // to print out if this read
}
inFile.close();
}
The file. First name, last name and phone number
CANDACE WITT 250-939-5404
THEODORE PERKINS 723-668-3397

Related

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

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 read 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.
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.
//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.

How to insert multiple data types of varying length into variables?

I need to insert the following values from a text file; however, I am a little confused on how to take in a name that may be of different length in C++ and spaced out differently. This is the Text file contents:
2.5 John Jones
4.0 Madonna
3.773 Ulysses S. Grant
I was thinking to have a loop that takes in a name then adds the subsequent string to the original name, but does C++ know how to do this and stop reading in when the data type changes? This is what I was thinking:
double gpa;
string name;
string temp;
while (file >> gpa >> name) {
while (file >> temp) {
name += " " + temp
}
}
You can use >> (stream extraction) for the double, and std::getline for the std::string, like this:
double gpa;
std::string name;
while (file >> gpa && std::getline(file, name)) {
std::cout << gpa << ":" << name << "\n";
}
I'd do this by defining a type Name that reads data as you want a name to be read, but overloading operator>> for that type. The operator>> for std::string stops reading at the first white space, but since you have a type that should include all data to the end of the line, you can define that type, and overload operator>> to act appropriately for that type:
class Name {
std::string content;
public:
friend std::istream &operator>>(std::istream &is, Name &n) {
return std::getline(is, n);
}
operator std::string() const { return content; }
};
With that, we can read the data about the way we'd like:
double gpa;
Name name;
while (file >> gpa >> name) {
// print them back out, formatted a bit differently:
std::cout << name << ": " << gpa << "\n";
}

How to stream a comma separated txt file to a class object?

How do I stream a line of comma separated txt file to an object that contain first name, last name and age variables? I want to overload the >> operator to do such operations.
std::istream& operator>>(std::istream& file, PersonData& obj) {
std::string line, firstName, lastName, age;
while (std::getline(file, line)) {
std::stringstream ss(line);
std::getline(ss,firstName,',');
std::getline(ss,lastName,',');
std::getline(ss, age,',');
firstName >> obj.firstName;
lastName >> obj.lastName;
std::stoi(age) >> obj.age;
}
return file;
}
Your operator>> should read a single entry from the file.
If you have a class
struct Person {
std::string first_name;
std::string last_name;
unsigned age;
};
You can use in/output operators:
std::ostream& operator<<(std::ostream& out,const Person& p) {
out << p.first_name << ", " << p.last_name << ", " << p.age;
return out;
}
std::istream& operator>>(std::istream& in,Person& p){
const auto comma = ',';
std::getline(in,p.first_name,comma);
std::getline(in,p.last_name,comma);
std::string temp;
std::getline(in,temp);
p.age = std::stoi(temp);
return in;
}
And then extract one Person at a time from the file:
int main() {
std::stringstream ss{"Peter, Fish, 42\nLaura, Peterson, 105"};
Person p1,p2;
ss >> p1 >> p2;
std::cout << p1 << "\n" << p2;
};
Output:
Peter, Fish, 42
Laura, Peterson, 105
Live example
To read all entries from a file you can use a vector and a loop:
std::vector<Person> persons;
Person entry;
while(stream >> entry) persons.push_back(entry);
PS: I missed to remove leading blanks from the names. I'll leave that to you ;)
john-wick.txt
John,Wick,50
main.cpp
#include <iostream>
#include <fstream>
struct PersonData {
string firstname;
string lastname;
int age;
friend std::istream& operator>>(std::istream& in, PersonData& obj) {
char comma;
in >> obj.firstname >> comma >> obj.lastname >> comma >> obj.age;
return in;
}
}
int main(int argc, char *argv[]) {
std::ifstream file("john-wick.txt");
PersonData john;
file >> john;
}
Here's a stencil for your class:
class My_Class
{
public:
friend std::istream& operator>>(std::istream& input, My_Class& mc);
private:
// members go here.
};
std::istream& operator>>(std::istream& input, My_Class& mc)
{
// Insert code to read comma separated values here.
return input;
}
The above allows you to stream input to your class:
My_Class mc;
std::vector<My_Class> database;
while (input_file >> mc)
{
database.push_back(mc);
}
Edit 1: Reading CSV
Based on the code you posted, I believe this is what you want:
std::istream& operator>>(std::istream& input, My_Class& mc)
{
std::getline(input, mc.firstName,',');
std::getline(input, mc.lastName,',');
input >> mc.age;
// Ignore till the end of the line:
input.ignore(10000, '\n');
return input;
}
Editing your question with a sample of the input file will allow readers to confirm or deny the content of the function.

Need help reading data from .txt file into an array C++

#include <iostream>
#include <fstream>
#include <string>
struct textbook //Declare struct type
{
int ISBN;
string title;
string author;
string publisher;
int quantity;
double price;
};
// Constants
const int MAX_SIZE = 100;
// Arrays
textbook inventory[MAX_SIZE];
void readInventory()
{
// Open inventory file
ifstream inFile("inventory.txt");
// Check for error
if (inFile.fail())
{
cerr << "Error opening file" << endl;
exit(1);
}
// Loop that reads contents of file into the inventory array.
pos = 0; //position in the array
while (
inFile >> inventory[pos].ISBN
>> inventory[pos].title
>> inventory[pos].author
>> inventory[pos].publisher
>> inventory[pos].quantity
>> inventory[pos].price
)
{
pos++;
}
// Close file
inFile.close();
return;
}
Hello,
I need assistance with this function. The goal of this function is to read in the information from a txt file and read it in to an array struct for a textbook.
The text file itself is already set up in the correct order for the loop.
My problem is that for the title section, the title of a book might be multiple words like 'My first book" for example. I know that I have to use a getline to take the line as a string to feed it into the 'title' data type.
I am also missing a inFile.ignore() somewhere but I don not know how to put it into a loop.
Presuming the input format is:
ISBN title author publisher price quantity price
i.e., the data members are line white space separated, you could define operator>> for your struct textbook, which could look something like:
std::istream& operator>> (std::istream& is, textbook& t)
{
if (!is) // check input stream status
{
return is;
}
int ISBN;
std::string title;
std::string author;
std::string publisher;
int quantity;
double price;
// simple format check
if (is >> ISBN >> title >> author >> publisher >> quantity >> price)
{
// assuming you additionally define a (assignment) constructor
t = textbook(ISBN, title, author, publisher, quantity, price);
return is;
}
return is;
}
Then to read your file you simply do:
std::ifstream ifs(...);
std::vector<textbook> books;
textbook b;
while (ifs >> b)
{
books.push_back(b);
}
Regarding the use of getline() see this answer.

C++ Extraction Operator for Class Functions

I'm not sure if operator overloading is what I'm looking for, but I need to know the best way to achieve the following in C++;
I have a class Employee (for simplicity) with just an ID number atm. Please assume the input file has an int number and some characters after (1 line shown only), such as:
1234 Charles Hammond
Here is the code so far. I am trying to use the extraction operator to get the integer and other data from input file to my class function (SetID);
class Employee
{
int employeeID;
public:
void SetID(int);
}
void Employee::SetID(int empID)
{
employeeID = empID;
}
int main(void)
{
int lineCounter = 4;
Employee emp;
//Create filestream objects and open
ifstream input;
ofstream output;
input.open("input.txt");
output.open("output.txt");
for (int i = 0; i < lineCounter; i++)
{
input >> emp.SetID(input.get()); //illegal? Best way to do this
}
//Close program
output.close();
input.close();
system("pause");
return 0;
}
I am simply trying to get the ID from the input file and store it in the class member "employeeID" to be used for calculations later.
One option is to overload the >> operator and make it a friend function in your Employee class.
Something like:
istream& operator>>( istream& in, Employee& emp )
{
in >> emp.employeeID;
return in;
}
And in your Employee class:
friend istream& operator>> (istream& in, Employee& emp);
There are a ton of ways to do this, each with pluses and minuses. The format of the data you're reading indicates you have one "record" per line, in which case that should be enforced somehow. The following does that by reading a line of data from the input file, then sending that line through a string stream for further processing:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
class Employee
{
// friend this operator, as we'll give it access to our
// private data members of our class.
friend std::istream& operator >>(std::istream& inp, Employee& obj);
int employeeID;
public:
void setID(int id) { employeeID = id; }
int getID() const { return employeeID; }
};
// extracts a single employee from a single input line taken from
// the passed input stream. the code below mandates one, and only
// one employee per line.
std::istream& operator >>(std::istream& inp, Employee& obj)
{
// used as a full-line-buffer to enforce single-record-per-line
std::string line;
if (std::getline(inp, line))
{
// think of it as an in-memory stream primed with our line
// (because that's exactly what it is).
std::istringstream iss(line);
// TODO: eventually you'll want this to parse *all* values from
// the input line, not just the id, storing each in a separate
// member of the Employee object being loaded. for now we get
// only the id and discard the rest of the line.
if (!(iss >> obj.employeeID))
{
// a failure to read from the line string stream should flag
// the input stream we read the line from as failed. we also
// output the invalid line to std::cerr.
inp.setstate(std::ios::failbit);
std::cerr << "Invalid format: " << line << std::endl;
}
}
return inp;
}
int main()
{
// open input and output files
std::ifstream input("input.txt");
// read at-most four employee lines from our file. If there are
// less than that or a read-error is encountered, we will break
// early.
Employee emp;
for (int i=0; i<4 && input >> emp; ++i)
{
// do something with this thing
std::cout << "Read Employee: " << emp.getID() << '\n';
}
system("pause");
return 0;
}