So, we have here 2 problems to solve.
- read data from a file
- split the read data into its parts
The format of the source text file is so called "CSV", for "Comma Separated Values". Instead of comma, any other meaningfull separator may be used.
So, what needs to be done?
- Open the file and check, if it could be opened
- In a loop read line by line from the file
- split the values into its parts
- store the parts in your struct
The challenge for you is here the "splitting" of the string. There are many many many potential solutions, let me share one often used approach with std::getline
.
std::getline basically reads characters from an input stream and places them into a string. Reading is done until a delimiter is found. If you do not specifically provide a delimiter as input parameter, then '\n' is assumed. So, it will read a complete line from a stream (file).
Then, because many people do not understand the pitfalls in using a mix of formatted and unformatted input, the read line is put into a std::istringstream
. This is also more robust/resilient against problems Then we can extract the parts of the string again with using std::getline
.
One potential example could be:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
class Student
{
public:
std::string fName{};
std::string sName{};
int mark{};
};
int main() {
// Open file and check, if it could be opened
if (std::ifstream sourceFileStream{ "file.txt" }; sourceFileStream) {
// The file could be opened. Define a vector, where we store all Student data
std::vector<Student> students{};
// Read all lines of the file
for (std::string line; std::getline(sourceFileStream, line); ) {
// Put the line into an std::istringstream, to extract the parts
std::istringstream iss{ line };
// Define a temporary Student for storing the parts
Student tempStudent{};
// Get the parts
std::getline(iss, tempStudent.fName, ';');
std::getline(iss, tempStudent.sName, ';');
// Use formatted input function to get the mark and convert it to an int
iss >> tempStudent.mark;
// So, now all parts are in the tempStudent. Add this to the result
students.push_back(tempStudent);
}
// For debug purposes, we show all read data
for (const Student& student : students)
std::cout << student.fName << '\t' << student.sName << "\t Mark: " << student.mark << '\n';
}
else
// File could not be opened. Show error message
std::cerr << "\n\nError: 'file.txt' could not be opened\n";
}
For the more experienced users. In C++ we often use a more object oriented approach. We store the data and the methods, operating on that data in the class.
C++ allows us to override the extraction >>
and inserter <<
operator. Those will then be part of the class and make IO easier.
Please see the little bit more advanced solution below:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
class Student
{
public:
std::string fName{};
std::string sName{};
int mark{};
friend std::istream& operator >> (std::istream& is, Student& s) {
if (std::string line{}; std::getline(is, line)) {
std::istringstream iss{ line };
std::getline(std::getline(iss, s.fName, ';'), s.sName) >> s.mark;
}
return is;
}
friend std::ostream& operator << (std::ostream& os, const Student& s) {
return os << s.fName << '\t' << s.sName << "\t Mark: " << s.mark;
}
};
class Students
{
public:
std::vector<Student> data{};
friend std::istream& operator >> (std::istream& is, Students& s) {
s.data = { std::istream_iterator<Student>(is),{} };
return is;
}
friend std::ostream& operator << (std::ostream& os, const Students& s) {
for (const Student& d : s.data) os << d << '\n';
return os;
}
};
int main() {
// Open file and check, if it could be opened
if (std::ifstream sourceFileStream{ "file.txt" }; sourceFileStream) {
// The file could be opened. Define a instance of Students
Students students{};
// Read all students
sourceFileStream >> students;
// Show all data
std::cout << students;
}
else
// File could not be opened. SHow error message
std::cerr << "\n\nError: 'file.txt' could not be opened\n";
}