Reading in a .txt file word by word to a struct in C++ - c++

I am having some trouble with my lab assignment for my CMPT class...
I am trying to read a text file that has two words and a string of numbers per line, and the file can be as long as anyone makes it.
An example is
Xiao Wang 135798642
Lucie Chan 122344566
Rich Morlan 123456789
Amir Khan 975312468
Pierre Guertin 533665789
Marie Tye 987654321
I have to make each line a separate "student", so I was thinking of using struct to do so, but I don't know how to do that as I need the first, last, and ID number to be separate.
struct Student{
string firstName;
string secondName;
string idNumber;
};
All of the tries done to read in each word separately have failed (ended up reading the whole line instead) and I am getting mildly frustrated.
With the help from #Sylence I have managed to read in each line separately. I am still confused with how to split the lines by the whitespace though. Is there a split function in ifstream?
Sylence, is 'parts' going to be an array? I saw you had indexes in []'s.
What exactly does the students.add( stud ) do?
My code so far is:
int getFileInfo()
{
Student stdnt;
ifstream stdntFile;
string fileName;
char buffer[256];
cout<<"Please enter the filename of the file";
cin>>filename;
stdntFile.open(fileName.c_str());
while(!stdFile.eof())
{
stdFile.getLine(buffer,100);
}
return 0;
}
This is my modified and final version of getFileInfo(), thank you Shahbaz, for the easy and quick way to read in the data.
void getFileInfo()
{
int failed=0;
ifstream fin;
string fileName;
vector<Student> students; // A place to store the list of students
Student s; // A place to store data of one student
cout<<"Please enter the filename of the student grades (ex. filename_1.txt)."<<endl;
do{
if(failed>=1)
cout<<"Please enter a correct filename."<<endl;
cin>>fileName;
fin.open(fileName.c_str());// Open the file
failed++;
}while(!fin.good());
while (fin >> s.firstName >> s.lastName >> s.stdNumber)
students.push_back(s);
fin.close();
cout<<students.max_size()<<endl<< students.size()<<endl<<students.capacity()<<endl;
return;
}
What I am confused about now is how to access the data that was inputted! I know it was put into a vector, but How to I go about accessing the individual spaces in the vector, and how exactly is the inputted data stored in the vector? If I try to cout a spot of the vector, I get an error because Visual Studio doesn't know what to output I guess..

The other answers are good, but they look a bit complicated. You can do it simply by:
vector<Student> students; // A place to store the list of students
Student s; // A place to store data of one student
ifstream fin("filename"); // Open the file
while (fin >> s.firstName >> s.secondName >> s.idNumber)
students.push_back(s);
Note that if istream fails, such as when the file finishes, the istream object (fin) will evaluate to false. Therefore while (fin >> ....) will stop when the file finishes.
P.S. Don't forget to check if the file is opened or not.

Define a stream reader for student:
std::istream& operator>>(std::istream& stream, Student& data)
{
std::string line;
std::getline(stream, line);
std::stringstream linestream(line);
linestream >> data.firstName >> data.secondName >> data.idNumber;
return stream;
}
Now you should be able to stream objects from any stream, including a file:
int main()
{
std::ifstream file("data");
Student student1;
file >> student1; // Read 1 student;
// Or Copy a file of students into a vector
std::vector<Student> studentVector;
std::copy(std::istream_iterator<Student>(file),
std::istream_iterator<Student>(),
std::back_inserter(studentVector)
);
}

Simply read a whole line and then split the string at the spaces and assign the values to an object of the struct.
pseudo code:
while( !eof )
line = readline()
parts = line.split( ' ' )
Student stud = new Student()
stud.firstName = parts[0]
stud.secondName = parts[1]
stud.idNumber = parts[2]
students.add( stud )
end while

Related

Read in file with tabs and spaces

I have a text file in this format:
Petroleum Engineering 94600 175500
Marine Engineering 73900 123200
Economics and Mathematics 60000 122900
Geophysics 54100 122200
Cognitive Science 54000 121900
What I have is course name, average early career pay, and mid career pay, all separated by tabs. The course names with multiple words are separated by spaces.
I want to read the course name and put it in one variable, the first pay in a second variable, and the third pay in a third variable.
int main(){
ifstream in;
in.open("Salaries.txt");
string course;
int mid;
int avg;
if (in.fail()){
cout<< "failed to open file";
exit(1);
}
while(!in.eof()){
in >> course >> avg >> mid;
cout << course<<endl;
}
in.close();
}
When I compile this code, it outputs nothing, and the program does not exit or terminate.
Someone in comments pointed out that using eof() is not recommended, so I tried thus instead:
while(in >> course >> sm >> lg){
cout << course << endl;
}
The process exits without outputting anything to the screen. I tried it on a input file that looks something like this:
NCORES 1
NEW 0
CORE 100
INPUT 5000
CORE 20
And it takes the string and puts it into one variable, and takes the number and puts it into another variable, and prints the correct output. So the problem is the white space between the words in the cours name in the original file, and I don't know how to account for that.
Although your code does have other problems, the problem you're running into is from the fact that operator>> for a string stops reading at the first white space it encounters. That means on the first line, it reads Petroleum into course, then tries to read Engineering into avg. Since avg is a number, that doesn't work, so the conversion fails. From there, all further attempts at reading from the stream fail.
To fix that, you probably want to use std::getline to read the course name. It allows you to specify the character that will end the string it reads. In this case, you apparently want to pass a tab character ('\t') for that parameter.
If I were doing it, I'd probably put the three items into a struct, and overload operator>> for that struct:
struct course {
std::string name;
long early_pay;
long mid_pay;
friend std::istream &operator>>(std::istream &is, course &c) {
if (std::getline(is, c.name, '\t')) {
std::string temp;
std::getline(is, temp, '\t');
c.early_pay = std::stol(temp);
std::getline(is, temp);
c.mid_pay = std::stol(temp);
}
return is;
}
};
Then reading the data and printing out the course names would look something like this:
int main() {
std::istringstream input(
R"(Petroleum Engineering 94600 175500
Marine Engineering 73900 123200
Economics and Mathematics 60000 122900
Geophysics 54100 122200
Cognitive Science 54000 121900 )");
course c;
while (input >> c)
std::cout << c.name << '\n';
}
Use std::getline() to read lines from the file, and use std::istringstream to parse each line. You can then use std::getline() to read tab-delimited strings from each line. For example:
int main() {
ifstream in("Salaries.txt");
if (!in.is_open()) {
cout<< "failed to open file";
exit(1);
}
string line course;
int mid, avg;
while (getline(in, line)) {
istringstream iss(line);
getline(iss, course, '\t');
iss >> avg >> mid;
cout << course << endl;
}
return 0;
}

How to read from a file to constructor in C++?

I have a players.txt file where I need to read from and put my readings in a constructor and then I will make a list of these TennisPlayer objects. And I am stuck with how to do it. Well, the first thing is I read from file word by word or line by line but couldn't manage how to put my readings into constructor.
My constructor has five inputs:
TennisPlayer(string firstName, tring lastName, int ranking, int totalPoints, string country)
And part of my players.txt file is here:
Novak Djokovic 16790 Serbia
Andy Murray 8945 Great Britain
And secondly, how can take "Great Britain" as one string?
I am really new in C++ and in a desperate position. Thank you all for your help.
Create a stream from a file and then pass it to a class like this. It will iterate over the file, store the values in a vector and then initialise a vector of those objects in the constructor. To read the country, we keep reading in words until we find the end of the line. Therefore, I am working under the assumption that each tennis player is specified in a single line.
Note that there is no error checking here, you may wish to add that
class TennisPlayersList
{
public:
struct TennisPlayer
{
std::string first_name;
std::string second_name;
int ranking;
int total_points;
std::string country;
};
TennisPlayersList(std::istream& filestream)
:players(ReadPlayersFromFile(filestream))
{}
private:
std::vector<TennisPlayer> players;
static std::vector<TennisPlayer> ReadPlayersFromFile(std::istream& filestream)
{
std::vector<TennisPlayer> p;
while (filestream.eof() == false)
{
p.push_back(ReadPlayer(filestream));
}
return p;
}
static TennisPlayer ReadPlayer(std::istream& filestream)
{
using namespace std;
TennisPlayer player;
std::string line;
getline(filestream, line);
std::stringstream ss(line);
ss >> player.first_name;
ss >> player.second_name;
ss >> player.ranking;
ss >> player.total_points;
// country could be several words, keep appending until we have finished
while (ss.good())
{
std::string country_part;
ss >> country_part;
if (player.country.empty())
player.country += country_part;
else
player.country += " " + country_part;
}
return player;
}
};
call with something like this
std::fstream players;
players.open("tennis_players.txt", std::ios::in);
TennisPlayersLists list(players);
players.close();

Having trouble parsing simple text file separated by commas [duplicate]

I'm trying to read a list of items from from a file and then store them into a vector. The issue is my code is adding the last item to the vector twice and I'm not sure why the it keeps reading the file even though the program has reached the end.
Here's what's in the text file. The "Oranges" line appears twice when I display the contents of the vector.
Apples-pounds-10 2
Oranges-pounds-5 6
Here's the code
//Read the contents of the list to a file
while (!inputFile.fail())
{
//Extract the line from the list
getline(inputFile,item_name,'-');
getline(inputFile,item_unit,'-');
inputFile >> item_amount;
inputFile >> item_price;
//Create an instance of the item object
Item New_Item(item_name, item_unit, item_amount,item_price);
//Push it to the list vector
list.push_back(New_Item);
}
//Close the file
inputFile.close();
This is a typical symptom of the while (!infile.fail()) anti-pattern.
I'd define a struct and overload operator>> for that type:
struct item {
std::string name;
std::string unit;
int amount;
int price;
};
std::istream &std::operator>>(std::istream &is, item &i) {
getline(is, i.name, '-');
getline(is, i.unit, '-');
is >> i.amount;
return is >> i.price;
}
With those defined, reading the data borders on trivial:
std::ifstream inputFile("fileNameHere");
std::vector<New_Item> items { std::istream_iterator<Item>(inputFile),
std::istream_iterator<Item>() };
[I changed it from list to vector, because, well, you really don't want list. You can change it back, but probably shouldn't.]
The problem is that the "fail" flag is not set until you make an attempt at reading some more data from the file. Here is a quick way of fixing this:
for (;;) {
//Extract the line from the list
getline(inputFile,item_name,'-');
getline(inputFile,item_unit,'-');
inputFile >> item_amount;
inputFile >> item_price;
if (inputFile.fail()) break;
//Create an instance of the item object
Item New_Item(item_name, item_unit, item_amount,item_price);
//Push it to the list vector
list.push_back(New_Item);
}
If this is for a learning exercise, and you have not learn the >> operator yet, this should do it. Otherwise, the operator>> approach is better.

Reading in from a txt file. Trouble parsing info

I want to read in scores from a txt file. The scores are going into a struct.
struct playerScore
{
char name[32];
int score, difficulty;
float time;
};
the text file looks like this
Seth 26.255 40 7
as one line, where each item is followed by a tab. (Name\t time\t score\t difficulty\n)
When I begin to read in the text, I don't know how to tell the program when to stop. The scores file could be any number of lines or score entries. This is what I have attempted.
hs.open("scores.txt", ios_base::in);
hs.seekg(0, hs.beg);
if (hs.is_open())
{
int currpos = 0;
while (int(hs.tellg()) != int(hs.end));
{
hs>> inScore.name;
hs >> inScore.time;
hs >> inScore.score;
hs >> inScore.difficulty;
hs.ignore(INT_MAX, '\n');
AllScores.push_back(inScore);
currpos = (int)hs.tellg();
}
}
I'm trying to make a loop that will read in a line of code into a temp struct for the data, then push that struct into a vector of structs. Then update the currpos variable with the current location of the input pointer. However, the loop just gets stuck on the condition and freezes.
There are a multitude of ways to do this, but the following is likely what you're looking for. Declare a free-operator for extracting a single-line definition of a player-score:
std::istream& operator >>(std::istream& inf, playerScore& ps)
{
// read a single line.
std::string line;
if (std::getline(inf, line))
{
// use a string stream to parse line by line.
std::istringstream iss(line);
if (!(iss.getline(ps.name, sizeof(ps.name)/sizeof(*ps.name), '\t') &&
(iss >> ps.time >> ps.score >> ps.difficulty)))
{
// fails to parse a full record. set the top-stream fail-bit.
inf.setstate(std::ios::failbit);
}
}
return inf;
}
With that, your read code can now do this:
std::istream_iterator<playerScore> hs_it(hs), hs_eof;
std::vector<playerScore> scores(hs_it, hs_eof);
I dont think that you can just >> from your file. Do you think it will take everything till \t? :)
You can try to take for example token with strtok()
I guess it can use '\t' to split string and take for each variable via this function needed part of string
In case if it strtok() doesnt work that way i guess you can just copy till '\t' in sub-loop
You can do like this
playerScore s1;
fstream file;
file.open("scores.txt", ios::in | ios::out);
while(!file.eof()) //For end of while loop
{
file.read(s1, sizeof(playerScore));//read data in one structure.
AllScores.push_back(s1);
}

Every other line of data is skipped when reading and storing data from a file

I'm new to C++ and I'm having a little trouble when it comes to reading lines of data from a text file. Let's say I have an unknown number of lines in a text file, with each line in the same format: int string double . The only thing that will be definite is a space will separate each piece of data on a given line. I'm using an array of structs to store the data. The code below works great except that it skips a line of input after each loop. I've tried inserting various ignore() statements and still can't get it to read each line, only every other line. If I rewrite some of the getline statements at the end, then the wrong data starts getting stored for the variables after the first loop.
Text file might look like this:
18 JIMMY 71.5
32 TOM 68.25
27 SARAH 61.4
//code
struct PersonInfo
{
int age;
string name;
double height;
};
//..... fstream inputFile; string input;
PersonInfo *people;
people = new PersonInfo[50];
int ix = 0;
getline(inputFile, input, ' ');
while(inputFile)
{
people[ix].age = atoi(input.c_str());
getline(inputFile, input, ' ');
people[ix].name = input;
getline(inputFile, input, ' ');
people[ix].height = atof(input.c_str());
ix++;
getline(inputFile, input, '\n');
getline(inputFile, input, ' ');
}
I'm sure there are more advanced ways to do this, but like I said I'm pretty new to C++ so if there are just some slight modifications to the code above, that would be great. Thanks!
You can do the file reading as follows:
int ix = 0;
int age = 0;
string name ="";
double height = 0.0;
ifstream inputFile.open(input.c_str()); //input is input file name
while (inputFile>> age >> name >> height)
{
PersonInfo p ={age, name, height};
people[ix++] = p;
}
You've made this whole code ridiculously complicated.
struct PersonInfo
{
int age;
string name;
double height;
};
std::vector<PersonInfo> people;
PersonInfo newPerson;
while(inputFile >> newPerson.age >> newPerson.name >> newPerson.height)
people.push_back(std::move(newPerson));
Your problem is because first your read each bit of data one at a time from the file, then a whole line from teh file, then each bit of data one at a time from the file again. Maybe what you intended was more like this?
std::string fullline;
while(std::getline(inputFile, fullline)) {
std::stringstream linestream(fullline);
std::getline(linestream, datawhatever);
....
}
By the way, more idiomatic code might look like more like this:
std::istream& operator>>(std::istream& inputFile, PersonInfo& newPerson)
{return inputFile >> newPerson.age >> newPerson.name >> newPerson.height;}
{ //inside a function
std::ifstream inputFile("filename.txt");
typedef std::istream_iterator<PersonInfo> iit;
std::vector<PersonInfo> people{iit(inputFile), iit()}; //read in
}
Proof it works here