Я в основном сконцентрировался на добавлении перегрузок для operator<<
и operator>>
, поскольку вы проявили интерес к ним ранее и описали их действия в комментариях в коде.
Поскольку вы смешиваете ввод и вывод из потоков, разделенных запятыми, и других потоков. Я добавил адаптер для потоковой передачи CSV
, а также перегрузки для потоковой передачи пользователю / от пользователя.
Сначала создайте class
, чтобы сохранить все данные, которые принадлежат вместе в одной записи данных. Я сделал это просто struct
здесь, то есть class
с public
доступом к своим членам по умолчанию.
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
// your student record
struct student {
std::string name; // It's usually good to have larger types first so name goes first
int roll;
int math;
int phy;
int chem;
int bio;
};
// read a student from an istream (like std::cin) - whitespace separated
std::istream& operator>>(std::istream& is, student& s) {
return is >> s.roll >> s.name >> s.math >> s.phy >> s.chem >> s.bio;
}
// write a student to an ostream (like std::cout)
std::ostream& operator<<(std::ostream& os, const student& s) {
return os << "Details of Roll " << s.roll << ":\n"
<< "Name: " << s.name << '\n'
<< "Maths: " << s.math << '\n'
<< "Physics: " << s.phy << '\n'
<< "Chemistry: " << s.chem << '\n'
<< "Biology: " << s.bio << '\n';
}
//--------------------------------------------------------------------------------------
// An adapter for comma separated streaming
struct CSVStudent {
CSVStudent(student& s) : stud(s) {}
CSVStudent(const CSVStudent&) = delete;
// The CSVStudent holds a reference to a "student"
student& stud;
};
// read a record from an istream - comma separated
std::istream& operator>>(std::istream& is, CSVStudent& csvstud) {
std::string line;
student& s = csvstud.stud; // an alias to the student to have to type less
if(std::getline(is, line)) { // read a complete line
// put the line in an istringstream for extraction:
std::istringstream ss(line);
char delim; // a dummy for reading commas
// Extract the comma separated values. "delim" is not checked so it could be
// any char breaking up the int:s.
//
// The below does things in the following order:
// 1. "ss >> s.roll >> delim"
// This extracts roll and a comma and returns
// a reference to ss, which is used in 2.
// 2. std::getline(ss, s.name, ',')
// Extracts a string until a comma is encountered.
// 3. Normal extraction for the rest of the int:s with the
// dummy variable "delim" where the commas are supposed to be.
if(not(std::getline(ss >> s.roll >> delim, s.name, ',') >> s.math >> delim >>
s.phy >> delim >> s.chem >> delim >> s.bio)) {
// If we get here, the extraction from the istringstream failed, so set
// the failstate on the istream too. Note the "not" on the line above.
is.setstate(std::ios::failbit);
}
}
return is;
}
// write a record to an ostream - comma separated
std::ostream& operator<<(std::ostream& os, const CSVStudent& csvstud) {
const student& s = csvstud.stud;
os << s.roll << ',' << s.name << ',' << s.math << ',' << s.phy << ',' << s.chem
<< ',' << s.bio << '\n';
return os;
}
//--------------------------------------------------------------------------------------
// get all students in the file as a std::vector<student>
std::vector<student> read_student_file(const std::string& filename) {
std::vector<student> retval;
std::ifstream fin(filename);
if(fin) { // file opened successfully
student stud;
CSVStudent csvstud{stud}; // holds a reference to stud
// loop for as long as student records can be read successfully
while(fin >> csvstud) // use the csv sdapter
retval.push_back(stud); // and put the stud in the vector
}
return retval;
}
//--------------------------------------------------------------------------------------
void create(const std::string& filename) {
// open an existing csv file or creates a new file.
std::ofstream fout(filename, std::ios::out | std::ios::app);
if(fout) {
std::cout << "Enter the details of 5 students:"
" roll name maths phy chem bio\n";
// Read the input
for(int i = 0; i < 5; i++) {
student stud;
std::cout << (i + 1) << ": ";
if(std::cin >> stud) {
// Insert the data to file if one was entered successfully
fout << CSVStudent(stud); // uses the adapters operator<<
} else {
std::cerr << "You failed to enter data for student " << (i + 1) << '\n';
break;
}
}
}
}
//--------------------------------------------------------------------------------------
int main() {
std::string filename = "reportcard.csv";
std::vector<student> students = read_student_file(filename);
std::cout << "There are " << students.size() << " students in the file.\n";
if(not students.empty()) {
// show the last record if there are any records in the file
std::cout << "Record " << students.size() << " is:\n\n";
std::cout << students.back() << '\n';
}
// create 5 new records
create(filename);
}
Если reportcard.csv
содержит это:
1,Ted,1,2,3,4
2,Foo,2,3,4,5
3,Bar,3,4,5,6
4,Baz,4,5,6,7
5,Bork,5,6,7,8
Программа должна запуститься так:
There are 5 students in the file.
Record 5 is:
Details of Roll 5:
Name: Bork
Maths: 5
Physics: 6
Chemistry: 7
Biology: 8
Enter the details of 5 students: roll name maths phy chem bio
1: <and here is where you're supposed to enter the first of 5 new students>