How to assign class values to vector<string>? - c++

I have a large textfile in which each line represents a city with postalcode and state.
It is written like this:
Brandenburg 35432 Potsdamm
Niedersachsen 35698 Hannover
I've already read the file in a vector and I have written a class and want to assign the classvalues to the vector.
class City
{
private:
float lat; //latitude
float lon; //longitude
public:
City cityclass(std::string state, std::string zipCode, std::string name);
//std::string name;
//std::string state;
//std::string zipCode;
float getLatitude() const
{
return lat;
}
float getLongitude() const
{
return lon;
}
};
So I have a class with std::string zipCode, the state and the cityname. I assume that this would be better to work with, especially when I want to be able to search for city's by zip or name.
How can I realize this? I thought about to simply modify my while-loop as it follows, but I'm realy not sure if this is the way to go.
Here is my full code:
class City
{
private:
/*float lat; //latitude
float lon; //longitude*/
public:
std::string zipCode;
std::string name;
std::string state;
/*float getLatitude() const
{
return lat;
}
float getLongitude() const
{
return lon;
}*/
};
int main ()
{
std::ifstream input("bundesland_plz_ort_de.txt");
//initilazing a vector of type string to store the data
std::vector<City> cityVector;
City city; //creating instance of class
//check if file can be accessed
if(!input)
{
std::cout << "ERROR!\tFile could not be opened!" << std::endl;
}
else
{
while(input >> city.state >> city.zipCode >> city.name)
{
cityVector.push_back(city);
}
input.close(); // close after finishing
}
}

I would recommend a slightly different approach. You defined a class City, but you read the data outside of the class.
In C++ we should put data on operations that are working on that data, all in one class. In this case you would (in your class) overwrite the inserter and extractor operator. The class knows, how to read and write its data. Even if you change the algorithm later, the rest of the code will work without modification.
In the following example code I put an ultra simple extractor and inserter (No error checking). Reading all data from the source file is then just one simple statement.
It is the definition of the variable "cl" as std::vector, using its range constructor. Very short and simple.
Usage of range constructor for std::vector.
We can define the std::vector without template argument. The compiler can deduce the argument from the given function parameters. This feature is called CTAD ("class template argument deduction").
Additionally, you can see that I do not use the "end()"-iterator explicitely.
This iterator will be constructed from the empty brace-enclosed initializer list with the correct type, because it will be deduced to be the same as the type of the first argument due to the std::vector constructor requiring that.
Having modified the class as described, you can then use all algorithm from the std library.
Please see:
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <fstream>
struct City {
// Data
std::string state{};
std::string zipCode{};
std::string name{};
// Member functions
// Extractor
friend std::istream& operator >> (std::istream& is, City& c) {
return is >> c.state >> c.zipCode >> c.name;
}
// Inserter
friend std::ostream& operator << (std::ostream& os, const City& c) {
return os << "\nState: " << c.state << "\nZip Code: " << c.zipCode << "\nName: " << c.name;
}
};
int main() {
// Try to open file and check, if it worked
if (std::ifstream sourceFile("r:\\bundesland_plz_ort_de.txt"); sourceFile) {
// Read complete source file into a city list
std::vector cl(std::istream_iterator<City>(sourceFile), {});
// Give some Debug output
std::copy(cl.begin(), cl.end(), std::ostream_iterator<City>(std::cout, "\n"));
}
else {
std::cerr << "\nError: Source file could not be opened\n";
}
}
Of course there are many other possible solutions . . .

just go on
first obtaining the number of object approximately by a loop precede it to count the total space delimited string then it's divided by the number of member data
// ...
//City city; //creating instance of class
if(!input)
{
std::cout << "ERROR!\tFile could not be opened!" << std::endl;
}
else if (input.is_open()) {
string buf(25);
int i=0;
while( input >> buf) ++i;
std::vector<City> cityVector(i /3 +5); // the number of member data plus some extra for sureness
input.clear();
input.seekg(0, ios::beg); // point back to start
i=0;
while( input >> cityVector[i].state >> cityVector[i].zipCode >> cityVector[i].name) ++i;
input.close(); // close after finishing
}
//..
this way need estimate the array size earlier approximately plus some guarding amount, then can resize, refit it eg. cityVector.resize(i+1)

Related

reading a txt file separated by commas into arrays C++ cpp

C++ question!
I have a .txt file with this info:
james, watson
brittany,blake
roger,tra4#pos
jonathan, pote5
amber,Trisa123!
where the first column is name and the second one is the Id of website users.
I need to read this file and then store the information into 2 arrays:
name[]
user_Id []
Could you please help me? I found the solution for saving it into a 2d vector but I prefer to save it as arrays since I need to compare the string values with another string (received by user to check if her name/user Id is already in the system or not)
I found the solution for saving it into a 2d vector but not for arrays.
I will show you your requested solution, but I am sorry to inform you that the solution approach is wrong. For various reasons. First, and most important: In C++ C-Style arrays should in general not not be used.
C-Style arrays have fixed size and are not dyanmic. So, you will always come up with a magic number of an estimated max size. The correct approach would be to use a dynamic container. And for your solution, the std::vector is most appropriate.
Then, it is a very bad idea to have to separate arrays for related data. The correct approach is to put related data in a struct and then create a std::vector of this struct. Otherwise you will have always to maintain and handle always 2 arrays, and you may even lose the sync between related data.
Anyway, I will first show you a solution following your idea:
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
using namespace std;
const unsigned int MagicNumberForMaxArraySize = 42;
int main() {
// Define Arrays to hold the user and their IDs
string user[MagicNumberForMaxArraySize]{};
string user_ID[MagicNumberForMaxArraySize]{};
// Open the file and check, if it could be opened
ifstream ifs("test.txt");
if (ifs.is_open()) {
unsigned int index = 0;
// Read all lines and put result into arrays
while ((index < MagicNumberForMaxArraySize) and
(getline(getline(ifs, user[index], ',') >> ws, user_ID[index]))) {
// Now we have read a comlete line. Goto next index
++index;
}
// Show debug output
for (unsigned int i = 0; i < index; ++i)
cout << "User: " << user[i] << "\tID: " << user_ID[i] << '\n';
}
else
cout << "\n\n*** Error: Could not open source file\n\n";
}
But I would not recommend to go on with that. The next improvement would be to use a struct and then an array of struct. Additionaly, I will get rid of using namespace std; which should never be used. And, I initialize varaibles with the universal initializer.
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
const unsigned int MagicNumberForMaxArraySize = 42;
struct Data {
std::string user{};
std::string ID{};
};
int main() {
// Define array for our needed data
Data data[MagicNumberForMaxArraySize];
// Open the file and check, if it could be opened
std::ifstream ifs("test.txt");
if (ifs.is_open()) {
unsigned int index = 0;
// Read all lines and put result into arrays
while ((index < MagicNumberForMaxArraySize) and
(std::getline(std::getline(ifs, data[index].user, ',') >> std::ws, data[index].ID))) {
// Now we have read a comlete line. Goto next index
++index;
}
// Show debug output
for (unsigned int i = 0; i < index; ++i)
std::cout << "User: " << data[i].user << "\tID: " << data[i].ID<< '\n';
}
else
std::cout << "\n\n*** Error: Could not open source file\n\n";
}
Evolution:
We will now introduce an object oriented principle . Data and methods operating on this data shall be in one class or struct. Hence, we will add IO methods to the struct, and add an aditional struct for holding all users. Also, the new if-statement with initializer can be used. And of course the std::vector.
Please see:
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <vector>
// Struct to hold properties for one user
struct User {
std::string name{};
std::string ID{};
// Simple extraction
friend std::istream& operator >> (std::istream& is, User& user) {
std::getline(std::getline(is, user.name, ',') >> std::ws, user.ID);
return is;
}
// Simple inserter
friend std::ostream& operator << (std::ostream& os, const User& user) {
return os << "User: " << user.name << "\tID: " << user.ID;
}
};
// This class will contain all users
struct Data {
std::vector<User> users{};
// Simple extraction
friend std::istream& operator >> (std::istream& is, Data& d) {
// Delete potential existing old data
d.users.clear();
// Now read all users
for (User temp{}; is >> temp; d.users.push_back(std::move(temp)));
return is;
}
// Simple inserter
friend std::ostream& operator << (std::ostream& os, const Data& d) {
for (const User& u : d.users) os << u << '\n';
return os;
}
};
int main() {
// Open the file and check, if it could be opened
if (std::ifstream ifs("test.txt");ifs) {
// Read all data and show result
if (Data data{}; not (ifs >> data).bad())
std::cout << data;
}
else
std::cout << "\n\n*** Error: Could not open source file\n\n";
}
You can also use strtok() from cstring library to split string into tokens: Split string in C/C++

Reading .txt file into array of struct

I'm a beginner in programming and i'm trying to read my .txt file into an array of struct in this program which after that display the data and then sort it, but the program only reads the first line and the loop won't stop until arraysize.
The file data looks like this:
ID NAME ADDRESS AGE
The Code:
#include <iostream>
#include <fstream>
#include <string>
#include <conio.h>
using namespace std;
struct bio
{
char name[50], address[50];
int id, age;
};
int main()
{
int i = 0, arraysize = 1000;
bio b[arraysize];
fstream data;
data.open("biodata.txt");
while(data.read((char*)&b, sizeof(b[i])))
{
for (i = 1; i < 1000; i++)
{
data >> b[i].id >> b[i].name >> b[i].address >> b[i].age;
}
}
for (i = 0; i < 1000; i++)
{
cout << b[i].id << " " << b[i].name << " " << b[i].address << " " << b[i].age << " " << endl;
}
data.close();
getch();
}
#include <iostream>
#include <fstream>
#include <string>
#define ARRAY_SIZE 1000
#define FILE_NAME "biodata.txt"
using namespace std;
struct Bio
{
int m_id;
string m_name;
string m_address;
int m_age;
};
int main()
{
Bio bio[ARRAY_SIZE];
ifstream data;
data.open(FILE_NAME);
if (!data)
{
cout << "not file " << FILE_NAME;
return 0;
}
for (int i = 0; i < ARRAY_SIZE && data.good(); ++i)
{
data >> bio[i].m_id >> bio[i].m_name >> bio[i].m_address >> bio[i].m_age;
}
for (int i = 0; i < ARRAY_SIZE ; ++i)
{
cout << bio[i].m_id << " " << bio[i].m_name << " " << bio[i].m_address << " " << bio[i].m_age << " " << endl;
}
data.close();
}
a few comments:
for what conio lib?
struct (bio) start with capital letter
don't use in char array in c++, you have string for this.
separate the variables to separate lines (bot "char name[50], address[50];")
better to rename members to m_X
about your "arraysize". if it const number you decide, do it with #define. if you need the whole file, you don't need it at all. (the file name too)
ifstream and not fstream data. you need just read. you don't want to change your data with some mistake.
check it the file opened well
in your code you check the while just before the loop.
in your condition loop check data.good(). it check it not eof and he file is readable.
read command is for binary file
it's better to separate the load file and print data to 2 differents functions. I didn't do it for save on your template
The following is maybe a little complicated for beginners, but since we are talking about C++, we should look also to a "more" objective oriented approach.
You designed a class, called bio. In object oriented languages you will put all data for an object and also all functions that operate on this data in the class. So you need to add member functions. The idea is that you encapsulate all data in an object. The outside world should not know anything about the details of the class. You just access it via member functions. And if you want to make changes later than you will do this within the member functions of the classes. And the rest of the program will continue to work.
Additionally we should definitely use C++ language features. For examples you should use std::string for strings and not Plain old C-Style char arrays. You should basically never use C-Style arrays in C++. Instead, please use STL container.
So, then let's design a class with data members and member functions. Since at the moment we just need input and output functionality, we overwrite the inserter and extractor operator. These operators know abot the data and behaviour of the class and will take care.
See the following program:
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <sstream>
struct Bio
{
// Data
unsigned int id{};
std::string name{};
std::string address{};
unsigned int age{};
// Overload extractor operator to read all data
friend std::istream& operator >> (std::istream& is, Bio& b) {
std::string textLine{};
if (std::getline(is, textLine)) {
std::istringstream textLineStream{textLine};
textLineStream >> b.id >> b.name >> b.address >> b.age;
}
return is;
}
// Overload inserter operator to print the data
friend std::ostream& operator << (std::ostream& os, const Bio& b) {
return os << b.id << " " << b.name << " " << b.address << " " << b.age;
}
};
std::istringstream sourceFile{R"(1 John Address1 31
2 Paul Address2 32
3 Ringo Address3 33
4 George Address4 34
)"};
int main()
{
// Define Variable and read complete source file
std::vector<Bio> bio{std::istream_iterator<Bio>(sourceFile), std::istream_iterator<Bio>()};
// Sort the guys by name
std::sort(bio.begin(), bio.end(), [](const Bio& b1, const Bio& b2){ return b1.name < b2.name;});
// Show output on screen
std::copy(bio.begin(),bio.end(),std::ostream_iterator<Bio>(std::cout, "\n"));
return 0;
}
Some comments. On StackOverflow, I cannot use files. So in my example program, I use a std::istringstream instead. But this is also an std::istream. You can use any other std::istream as well. So if you define an `````std::ifstreamto read from a file, then it will work in the same way as thestd::istringstream````.
And please see. The extractor operator does the whole work of reading the source File. It is encapsulated. No outside function needs to know, how it does.
In the main function, we define a std::vector and use its range contructor to specifiy where the data comes from. We give it the std::istream_iterator, which iterates over the input data and calls the extractor operator until verything is read.
Then we sort by names and copy the result to the output.
You may notice that fields in your input data are separted by space. This does in general not work for none atomic data. The name could exist of 2 parts and the address can have a street and a city. For this CSV (Comma separated Values) files have been invented.
Please see a more realistic soultion below.
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <sstream>
#include <regex>
struct Bio
{
// Data
unsigned int id{};
std::string name{};
std::string address{};
unsigned int age{};
// Overload extractor operator to read all data
friend std::istream& operator >> (std::istream& is, Bio& b) {
std::string line{};
std::regex re{";"};
if (std::getline(is, line)) {
std::vector<std::string> token{std::sregex_token_iterator(line.begin(), line.end(), re, -1), std::sregex_token_iterator()};
if (4 == token.size()) {
b.id = std::stoul(token[0]);
b.name = token[1];
b.address = token[2];
b.age = std::stoul(token[3]);
}
}
return is;
}
// Overload inserter operator to print the data
friend std::ostream& operator << (std::ostream& os, const Bio& b) {
return os << b.id << ", " << b.name << ", " << b.address << ", " << b.age;
}
};
std::istringstream sourceFile{R"(1; John Lenon; Street1 City1; 31
2; Paul McCartney; Street2 City2; 32
3; Ringo Starr; Street3 City3; 33
4; George Harrison; Address4; 34
)"};
int main()
{
// Define Variable and read complete source file
std::vector<Bio> bio{std::istream_iterator<Bio>(sourceFile), std::istream_iterator<Bio>()};
// Sort the guys by name
std::sort(bio.begin(), bio.end(), [](const Bio& b1, const Bio& b2){ return b1.name < b2.name;});
// Show output on screen
std::copy(bio.begin(),bio.end(),std::ostream_iterator<Bio>(std::cout, "\n"));
return 0;
}
We have a new source format and main is unchanged. Just the extractor operator is modified. Here we are using a different iterator to get the source data.

Understanding reading txt files in c++

I am trying to understand reading different txt file formats in c++
I am currently trying to read a file formatted like this,
val1 val2 val3
val1 val2 val3
val1 val2 val3
When I read the file in and then cout its contents I only get the first line then a random 0 0 at the end.
I want to save each value into its own variable in a struct.
I am doing this like this,
struct Input{
std::string group;
float total_pay;
unsigned int quantity;
Input(std::string const& groupIn, float const& total_payIn, unsigned int const& quantityIn):
group(groupIn),
total_pay(total_payIn),
quantity(quantityIn)
{}
};
int main(){
std::ifstream infile("input.txt");
std::vector<Input> data;
std::string group;
std::string total_pay;
std::string quantity;
std::getline(infile,group);
std::getline(infile,total_pay);
std::getline(infile,quantity);
while(infile) {
data.push_back(Input(group,atof(total_pay.c_str()),atoi(quantity.c_str())));
std::getline(infile,group);
std::getline(infile,total_pay);
std::getline(infile,quantity);
}
//output
for(Input values : data) {
std::cout << values.group << " " << values.total_pay << " " << values.quantity << '\n';
}
return 0;
}
What is the proper way to read this file in the the format I have specified? Do I need to specify to go to the next line after the third value?
Or should this be taking each value and putting them in to the right variable?
std::getline(infile,group);
std::getline(infile,total_pay);
std::getline(infile,quantity);
Your input processing has a number of issues. Your prevalent usage of std::getline in places where it is not needed isn't helping.
In short, per-line validation of input is generally done with a model similar to the following. Note that this requires the class provide a default constructor. We use an input-string-stream to process a single item from each line of input from the input file. If it was certain there was at-most one per line, we could forego the per-line processing, but it is a potential place for errors, so better safe than sorry. The mantra presented here is commonly used for per-line input validation when reading a stream of objects from a formatted input file, one item per line.
The following code defines the structure as you have it with a few extra pieces, including providing both an input and output stream insertion operator. The result makes the code in main() much more manageable.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
struct Input
{
// friends not needed if the members are public, but provided here
// in case you ever do make them protected or private (which you should)
friend std::istream& operator >>(std::istream& inp, Input& item);
friend std::ostream& operator <<(std::ostream& outp, Input const& item);
std::string group;
float total_pay;
unsigned int quantity;
// default constructor. sets up zero-elements
Input() : total_pay(), quantity()
{
}
Input(std::string groupIn, float total_payIn, unsigned int quantityIn)
: group(std::move(groupIn))
, total_pay(total_payIn)
, quantity(quantityIn)
{
}
// you really should be using these for accessors
std::string const& getGroup() const { return group; }
float getTotalPay() const { return total_pay; }
unsigned int getQuantity() const { return quantity; }
};
// global free function for extracting an Input item from an input stream
std::istream& operator >>(std::istream& inp, Input& item)
{
return (inp >> item.group >> item.total_pay >> item.quantity);
}
// global operator for inserting to a stream
std::ostream& operator <<(std::ostream& outp, Input const& item)
{
outp << item.getGroup() << ' '
<< item.getTotalPay() << ' '
<< item.getQuantity();
return outp;
}
int main()
{
std::ifstream infile("input.txt");
if (!infile)
{
std::cerr << "Failed to open input file" << '\n';
exit(EXIT_FAILURE);
}
// one line per item enforced.
std::vector<Input> data;
std::string line;
while (std::getline(infile, line))
{
std::istringstream iss(line);
Input inp;
if (iss >> inp) // calls our extaction operator >>
data.emplace_back(inp);
else
std::cerr << "Invalid input line: " << line << '\n';
}
// dump all of them to stdout. calls our insertion operator <<
std::copy(data.begin(), data.end(),
std::ostream_iterator<Input>(std::cout,"\n"));
return 0;
}
Provided the input is properly formatted, values like this:
group total quantity
group total quantity
will parse successfully. Conversely, if this happens:
group total quantity
group quantity
group total quantity
total quantity
the extractions of the second and fourth items will fail, and appropriate warning will be issued on std::cerr. This is the reason for using the std::istringstream intermediate stream object wrapping extraction of a single line per item.
Best of luck, and I hope it helps you out.
Check this solution
It is without error checks but with conversion to types
#include<iostream>
#include<sstream>
using namespace std;
int main()
{
string line="v1 2.2 3";//lets say you read a line to this var...
string group;
float total_pay;
unsigned int quantity;
//we split the line to the 3 fields
istringstream s(line);
s>>group>>total_pay>>quantity;
//print for test
cout<<group<<endl<<total_pay<<endl<<quantity<<endl;
return 0;
}

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

Write to a Vector of Type Class from a File

Saving the vector to a file works fine. But I'm looking for a simple way to load the saved data back into the vector.
This is a follow up question to two I asked previously.
1) C++ Trouble Inputting Data into Private Vector (invalid use)
2) Outputting Vector of Type Class
What's a simple way to iterate through the file and push_back() each element?
This is the class:
class Account
{
private:
string firstName;
string lastName;
string accountPass;
int accountID;
float accountBalance;
public:
static Account createAccount( int, float, string, string, string ); //creates new account
int getAccountID() const { return accountID; }
string getPass() const { return accountPass; }
string getFirstName() const { return firstName; }
string getLastName() const { return lastName; }
float getBalance() const { return accountBalance; }
friend std::ostream& operator << (std::ostream&, const Account&);
friend class BankingSystem;
}; //end of class Account
Account Account::createAccount( int ID, float balance, string pass, string first, string last )
{
Account a;
a.accountID = ID;
a.accountPass = pass;
a.firstName = first;
a.lastName = last;
a.accountBalance = balance;
return a;
}
std::ostream & operator << (std::ostream & os, const Account & acc)
{
os << setw(6) << acc.getAccountID();
os << setw(4) << acc.getPass();
os << setw(9) << acc.getFirstName();
os << setw(9) << acc.getLastName();
os << setw(9) << setprecision(2) << fixed << acc.getBalance();
return os;
}
If Accounts are the only thing written in your file you can read them all into your vector (or any push_back-able container) with this 1-liner:
std::copy(std::istream_iterator<Account>(file), std::istream_iterator<Account>(), std::back_inserter(vec));
You'll also need an operator>> analogous to the operator<< you already have.
Found the answer in this Question Using vector of user defined class type objects
for me it was solved by using:
while(!inBankSysFile.eof())
{
Account a;
inBankSysFile >> a.accountID;
inBankSysFile >> a.accountPass;
inBankSysFile >> a.firstName;
inBankSysFile >> a.lastName;
inBankSysFile >> a.accountBalance;
accounts_.push_back(a);
}
If you don't have any dynamic memory, you can read and write it to binary pretty easily using ifstream::read and ofstream::write and vector::data. Here's an example:
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
class Time
{
public:
Time(): hh(0),mm(0),ss(0) {}
Time(int h,int m,int s):hh(h),mm(m),ss(s) {}
int hh,mm,ss;
};
int main()
{
Time time1(11,22,33);
Time time2(44,55,66);
vector<Time> timeList;
timeList.push_back(time1);
timeList.push_back(time2);
vector<Time> timeList2;
timeList2.resize(2,Time());
ofstream fout;
fout.open("test.txt");
if(fout.is_open())
{
// vector.data returns a pointer to the beginning of its stored data
// 1st param: the location to read data from
// 2nd param: the amount of bytes to write to the file
fout.write((const char*)timeList.data(),sizeof(Time)*timeList.size());
fout.close();
}
ifstream fin;
fin.open("test.txt");
if(fin.is_open())
{
// 1st param: the location to write data to
// 2nd param: the amount of bytes to read from the file
// NOTE: make sure you've sized the vector appropriately before writing to it.
fin.read((char*)timeList2.data(),sizeof(Time)*timeList2.size());
for(int i=0;i<timeList2.size();++i) {
cout << timeList2[i].hh << ":" << timeList2[i].mm << ":" << timeList2[i].ss << "\n";
}
fin.close();
}
return 0;
}
NOTE: Reading/writing objects that use dynamic memory (including objects containing classes that contain dynamic memory, such as std::string), will require additional processing logic to handle reading and writing that data.
NOTE: Beware of variances in structural alignment padding when using the sizes of any objects.