Need help reading data from .txt file into an array C++ - 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.

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.

Read text file and store student info into a a vector [duplicate]

This question already has an answer here:
Read lines from text file and store into array
(1 answer)
Closed 1 year ago.
the text file looks something like this:
9528961 Adney Smith CS 4.2
9420104 Annalynn Jones EE 2.6
9650459 Bernadette Williams IT 3.6
...
there are 45 lines in the text file meaning 45 students. I have read the text file and when I run the program I get this:
9428167
Mason
Taylor
CS
4.8
9231599
Alexander
Jones
CS
2.3
My main file looks like this:
int main()
{
auto student = new Student<string>();
std::vector<string> students;
std::ifstream inputFile;
inputFile.open("enroll_assg.txt");
std::string line;
if(inputFile.is_open()){
while(std::getline(inputFile, line)){
std::istringstream iss(line);
std::string word;
while(iss >> word){
std::cout << word << std::endl;
for(int i = 0; i < 5; i++){
}
}
}
}
return 0;
}
Each student has 5 columns (id, fname, lname, department, gpa) and I need make a vector which includes all these student object. I need some help doing this so comments and answers are most welcome. Thank you.
IMHO, the best method is to use a struct or class to model or represent the data record you need to read.
struct Student
{
unsigned int id;
std::string first_name;
std::string last_name;
std::string major_code;
double gpa;
friend std::istream& operator>>(std::istream& input, Student& s);
};
std::istream& operator>>(std::istream& input, Student& s)
{
input >> s.id;
input >> s.first_name;
input >> s.last_name;
input >> s.major_code;
input >> s.gpa;
input.ignore(10000, '\n'); // Synchronize to next line.
return input;
}
Your input code could look like this:
std::vector<Student> database;
Student s;
//... open file.
while (student_file >> s)
{
database.push_back(s);
}
The above code will read each student record into a database, so you can analyze it.
Try something more like this instead:
int main()
{
std::ifstream inputFile("enroll_assg.txt");
if (inputFile.is_open()){
std::vector<Student<string>> students;
std::string line;
while (std::getline(inputFile, line)){
std::istringstream iss(line);
Student<string> student;
iss >> student.id;
iss >> student.fname;
iss >> student.lname;
iss >> student.department;
iss >> student.gpa;
students.push_back(student);
}
// use students as needed...
}
return 0;
}
Then, you should consider having Student overload the operator>>, which will greatly simplify the loop so you can do something more like this instead:
template<typename T>
std::ostream& operator>>(std::ostream &in, Student<T> &student)
{
std::string line;
if (std::getline(in, line))
{
std::istringstream iss(line);
iss >> student.id;
iss >> student.fname;
iss >> student.lname;
iss >> student.department;
iss >> student.gpa;
}
return in;
}
int main()
{
std::ifstream inputFile("enroll_assg.txt");
if (inputFile.is_open()){
std::vector<Student<string>> students;
Student<string> student;
while (inputFile >> student){
students.push_back(student);
}
// use students as needed...
}
return 0;
}
First this question is a duplicate of Read lines from text file and store into array which already has the answer you're looking for in this question.
The below shown program uses struct to represent a given Student and it also used a std::vector. You can use this program as a reference(starting point). It reads student information from the input text file and store that information in a vector of Student.
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
//this class represents a Student
class Student
{
public:
std::string firstName, lastName, courseName ;
unsigned long id = 0;
float marks = 0;
};
int main()
{
std::ifstream inputFile("input.txt");
std::string line;
std::vector<Student> myVec;//create a vector of Student objects
if(inputFile)
{
while(std::getline(inputFile, line))
{
Student studentObject;
std::istringstream ss(line);
//read the id
ss >> studentObject.id;
//read the firstname
ss >> studentObject.firstName;
//read the lastname
ss >> studentObject.lastName;
//read the courseName
ss >> studentObject.courseName;
//read the marks
ss >> studentObject.marks;
if(ss)//check if input succeded
{
myVec.emplace_back(studentObject);//add the studentObject into the vector
}
}
}
else
{
std::cout<<"File cannot be opened"<<std::endl;
}
//lets print out the elements of the vecotr to confirm that all the students were correctly read
for(const Student &elem: myVec)
{
std::cout << elem.id << ": "<<elem.firstName<<" "<<elem.lastName<<" "<<elem.courseName<<" "<<elem.marks <<std::endl;
}
return 0;
}
The output of the above program can be seen here.

How to read file using the overload operator>>?

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

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;
}

How to get the whole line where a given word is and store it in a variable?

i am a beginner in the C++ world, i need to get the whole line where a given word is and store it into a variable.
my TXt file has this structure :
clients.txt
085958485 Roland Spellman rolandl#gmail.com
090545874 KATHLEEN spellman kathleen1#hotmail.com
056688741 Gabrielle Solis desperate#aol.com
so the program requests to the user to enter the id of the person, the id is always the first number or word in the line.
the user enters then
090545874
the program has to be able to find the 090545874 in the text file and then get the whole line where it is stored into a variable.
i know how to find a word in a text file but i don't know how to get the whole line into a variable. so at the end my variable has to store
variable = 090545874 KATHLEEN spellman kathleen1#hotmail.com 4878554
after that, i am able to delete the entire line or record.
i use this code to enter the data into the txt file
struct person{
char id[10];
char name[20];
char lastname[20];
char email[10];
} clientdata;
ofstream clientsfile;
clientsfile.open ("clientes.dat" , ios::out | ios::app);
if (clientsfile.is_open())
{
cout<<" ENTER THE ID"<<endl;
cin>>clientdata.id;
clientsfile<<clientdata.id<<" ";
cout<<" ENTER THE NAME"<<endl;
cin>>datoscliente.name;
clientsfile<<clientdata.name<<" ";
cout<<" ENTER THE LAST NAME"<<endl;
cin>>clientdata.lastname;
clientsfile<<clientdata.lastname<<" ";
cout<<" ENTER THE LAST EMAIL"<<endl;
cin>>clientdata.email;
clientsfile<<clientdata.email<<" ";
then i request to the eu to enter the id
and what i need to do is not to find the id only, it's to get the whole line where the id is
so if the user enters 090545874 , i need to find it in the text file , but i need to get teh whole line in this case 090545874 KATHLEEN spellman kathleen1#hotmail.com
so i need to store that into a new variable
string newvariable;
newvariable = 090545874 KATHLEEN spellman kathleen1#hotmail.com
To read files one line at a time, you can use the std::getline function defined in the <string> header (I'm assuming you're using the fstream library as well):
#include <fstream>
#include <string>
int main(int argc, char** argv) {
std::ifstream input_file("file.txt");
std::string line;
while (true) {
std::getline(input_file, line);
if (input_file.fail())
break;
// process line now
}
return 0;
}
What's nice about the function std::getline, though, is that it allows for this much cleaner syntax:
#include <fstream>
#include <string>
int main(int argc, char** argv) {
std::ifstream input_file("file.txt");
std::string line;
while (std::getline(input_file, line)) {
// process line now
}
return 0;
}
thank all of you for your answers, I finally figured it out , I used this function :
bool mostshow(int option, string id)
{
if (option== 2 && id== id1)
return true;
if (option== 3 && id== id1)
return true;
return false;
}
and this other one
void showline(string field1, string field2, string field3, string field4, string field5, string field6, string field7)
{
string store;
store = field1+" "+field2+" "+field3+" "+field4+" "+field5+" "+field6+" "+field7;
cout<<endl;
}
and then in the main
ifstream myfile("clients.dat", ios::in);
if (!myfile)
{
cerr <<" CANNOT OPEN THE FILE!!"<<endl;
exit(1);
}
option=2;
myfile >> field1 >> field2 >> field3 >> field4 >>field5 >> field6 >> field7;
while (!myfile.eof())
{
if (mostshow(option, id))
{
showline(field1, field2, field3, field4, field5, field6, field7);
}
myfile >> field1 >> field1 >> field1 >> field1 >>field1 >> field1 >> field1;
}
myfile.close();
option variable is part of a switch statement which asks if you want to delete or modify the record, 2 means modify , 3 delete
You didn't say how you're reading the file, but the fgets function will do what you want.
Use ifstream, getline and unordered_map:
#include <fstream>
#include <string>
#include <sstream>
#include <exception>
#include <unordered_map>
using namespace std;
ifstream infile("mytextfile.txt");
if (!infile) {
cerr << "Failure, cannot open file";
cin.get();
return 0;
}
unordered_map<string, string> id2line;
string id, line;
while (getline(infile, line)) {
stringstream strstm(line);
strstm >> id;
id2line[id] = line;
}
Now you can do
cout << "Please enter an id: " << endl;
string id;
cin >> id;
try {
// unordered_map::at throws an std::out_of_range exception when the key doesn't exist
string line = id2line.at(id);
cout << "Info:\n " << line << endl;
} catch (out_of_range& e) {
cout << "No information by that id." << endl;
}
You could create a structure and have the structure read in its data by overloading the stream extraction operator:
struct Record
{
unsigned int id;
std::string first_name;
std::string last_name;
std::string email_addr;
friend std::istream& operator>>(std::istream& input, Record& r);
};
std::istream& operator>>(std::istream& input, Record&r)
{
input >> r.id;
input >> r.first_name;
input >> r.last_name;
getline(input, r.email_addr);
return input;
}
Edit 1:
Usage:
ifstream input_file("mydata.text");
Record r;
std::map<unsigned int, Record> container;
while (input_file >> r)
{
unsigned int id = r.id;
container[id] = r;
}
As far as storage is concerned look up the std::map structure and copy the ID field and use it as the key.
I still suggest that this work is a better candidate for a database or spreadsheet.