Problème lors de la lecture d'objets à partir d'un fichier en c ++
Je fais un petit projet universitaire où je dois ajouter, éditer et rechercher des enregistrements dans / à partir d'un fichier en utilisant le concept OOP. L'ajout dans un fichier fonctionne bien, mais chaque fois que j'essaie de lire un fichier, il imprime dans des textes illisibles. Voici le code complet et la sortie. main.cpp
#include <iostream>
#include <cstdlib>
#include <fstream>
#define MIN 20
#define MAX 100
#include "student.h"
using namespace std;
void add_student();
void edit_student();
void search_student();
void addToFile(const Student&);
Student* fetchFromFile();
int getFileSize();
void updateFile(Student*);
// Student stud[MAX];
int main()
{
int choice;
system("cls");
system("Color B0");
while(1)
{
cout<<"\n\t\tWhat do you want to do?"<<endl;
cout<<"\t\t----------------------"<<endl;
cout<<"\t\t1-Add student"<<endl;
cout<<"\t\t2-Edit student"<<endl;
cout<<"\t\t3-Search student"<<endl;
cout<<"\t\t4-Quit Program"<<endl;
cout<<"\t\t----------------------"<<endl;
cout<<"Enter your choice: ";
cin>>choice;
switch(choice)
{
case 1:
add_student(); //calling add_student function to add records.
break;
case 2:
edit_student();
break;
case 3:
search_student();
break;
case 4:
return 0;
break;
default:
cout<<"Invalid choice";
break;
}
}
return 0;
}
int Student::id = getFileSize() - 1; //Initialize id equals to size of file
// setData function of class Student definition
void Student :: setData()
{
// taking input from user
cout<<"Enter student roll no in format(1XXX): ";
cin>>roll;
cout<<"Enter student name: ";
cin>>name;
cout<<"Enter stduent date of birth(dd/mm/yy): ";
cin>>dob;
cout<<"Enter stduent phone no: ";
cin>>phone;
cout<<"Enter student address: ";
cin>>address;
stdId = Student::id;
}
void Student :: showData()
{
cout<<stdId<<" ";
cout<<roll<<" ";
cout<<name<<" ";
cout<<dob<<"\t";
cout<<phone<<" ";
cout<<address<<"\n\n";
}
const int Student :: getRoll()
{
return roll;
}
Student& Student::operator = (const Student& newObj)
{
stdId = newObj.stdId;
roll = newObj.roll;
name = newObj.name;
dob = newObj.dob;
phone = newObj.phone;
address = newObj.address;
return *this;
}
void add_student()
{
Student stud;
Student::incrementId();
stud.setData();
addToFile(stud); //adding records to file
system("CLS");
cout<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"---------------------------Student updated record Table---------------------------------"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"ID "<<"Roll "<<"Name "<<"DOB "<<"Phone no "<<"Address\n\n";
cout<<"--------------------------------------------------------------------------------"<<endl;
Student* student = fetchFromFile(); //getting records from file in array of objects
int length = getFileSize(); //getting length of array of objects
for(int i=0; i<(length-1); i++)
{
student[i].showData(); //showing all the data
}
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"---------------------------------FINISH-----------------------------------------"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"You want to add more?(Y/n): ";
char c;
cin>>c;
if(c=='y' || c=='Y')
{
add_student();
}
else{
system("pause");
}
}
void edit_student(){
//Showing existing record first before editing
cout<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"---------------------------Student Existing record Table---------------------------------"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"ID "<<"Roll "<<"Name "<<"DOB "<<"Phone no "<<"Address\n\n";
cout<<"--------------------------------------------------------------------------------"<<endl;
Student* student = fetchFromFile(); //fetching all records from file
int length = getFileSize();
for(int i=0; i<(length-1); i++)
{
student[i].showData();
}
int idnumber;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"Which ID number your want to edit: ";
cin>>idnumber; //Asking the user at which ID he wants to make a change.
//checking for valid id number
if(idnumber>length || idnumber<0)
{
cout<<"\nInvalid ID Number."<<endl;
}
//showing existing information about that specific record
cout<<"\nExisted information about this record.\n\n";
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"ID "<<"Roll "<<"Name "<<"Father\tCell no. "<<"DOB "<<"Address\n\n";
cout<<"--------------------------------------------------------------------------------"<<endl;
student[idnumber].showData();
cout<<"\n\nEnter new data for above shown record.\n\n";
student[idnumber].setData(); //Inputting data for that specific record.
updateFile(student);
cout<<"\n\nRecord updated successfully."<<endl;
cout<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"---------------------------Updated record Table---------------------------------"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"ID "<<"Roll "<<"Name "<<"DOB "<<"Phone no "<<"Address\n\n";
cout<<"--------------------------------------------------------------------------------"<<endl;
for(int i=0; i<(length-1); i++) //Showing updated record Table
{
student[i].showData();
}
}
void search_student(){
Student* student = fetchFromFile();
int fileLenth = getFileSize() - 1;
int searchkey;
cout<<"Enter roll_no of student you want to search: ";
cin>>searchkey; //roll_no as the search key can be entered by user.
for(int i=1; i<fileLenth; i++)
{
if(searchkey==student[i].getRoll()) //checking for roll no
{
student[i].showData();
}
}
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"---------------------------------FINISH-----------------------------------------"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
system("pause");
}
//FILE HANDLING
void addToFile(const Student& obj)
{
ofstream fout;
fout.open("records.txt", std::ofstream::app | std::ofstream::binary);
fout.write((char*)&obj, sizeof(obj));
cout<<"Added to file successfully!"<<endl;
fout.close();
}
Student* fetchFromFile()
{
int i=0;
Student obj;
Student* returnObj = new Student[MAX];
ifstream fin;
fin.open("records.txt", std::ifstream::binary);
while(!fin.eof())
{
fin.read((char*)&obj, sizeof(obj));
returnObj[i] = obj;
i++;
}
fin.close();
delete[] returnObj;
return returnObj;
}
int getFileSize()
{
int i=0;
Student obj;
ifstream fin;
fin.open("records.txt", std::ifstream::binary);
while(!fin.eof())
{
fin.read((char*)&obj, sizeof(obj));
i++;
}
fin.close();
return i;
}
void updateFile(Student* student)
{
ofstream fout;
fout.open("records.txt", std::ofstream::binary);
fout.write((char*)&student, sizeof(student));
fout.close();
}
fichier d'en-tête student.h
// A student class that hold students attributes like id, name, address and class
// Object of this class will be craeted to store student details
class Student
{
int stdId;
int roll;
std::string name;
std::string dob;
std::string phone;
std::string address;
public:
static int id; //we will increase 'id' whenever student is added to the record
//Member functions declaration
void setData(); //this function will take input from user and set the data to attributes of class
void showData(); //This function will give student data to user when called
static void incrementId()
{
id++;
}
const int getRoll();
Student& operator = (const Student&);
};
Exemple de sortie 1
Lorsque j'ajoute un objet étudiant au fichier
Exemple de sortie 2
Lire tous les enregistrements du fichier
Problème 1: Affichage de la valeur de garbage de id.
Exemple de sortie 3
Ajout d'un autre objet au fichier
Exemple de sortie 4
Lecture de tous les objets du fichier
Exemple de sortie 5
Maintenant est revenu et a choisi de modifier l'enregistrement
Problème 2: voyez comment les enregistrements s'impriment sous une forme illisible.
Pourquoi cela arrive-t-il. Maintenant, si je ferme le programme et l'exécute à nouveau, il s'affiche toujours dans un texte illisible. J'espère que vous obtenez mon problème. Je veux avoir des explications détaillées à ce sujet. Aussi, si j'ai commis d'autres erreurs diverses, merci de me le faire savoir. Je vous remercie!
Réponses
Student
est trop compliqué à lire avec des IO non formatées comme read
et write
. En termes techniques, il n'est pas trivialement copiable car il contient des std::string
s et string
n'est pas trivialement copiable.
La chose la plus simple à faire est d'abandonner read
et write
. La plupart de vos données sont des données de type chaîne, donc écrivez <<
, >>
surchargez Student
et stockez tout sous forme de texte.
friend std::ostream & operator<<(std::ostream & out,
const Student & stu)
{
out << stu.stdId << ',' <<stu.roll << ','<< stu.name... <<'\n';
return out;
}
La lecture des données est un peu plus délicate
friend std::istream & operator>>(std::istream & in,
Student & stu)
{
std::string line;
if (std::getline(in, line))
{
std::stringstream strm(line);
if (!(strm >> stu.stdId >> comma >> stu.roll >> comma) ||
!std::getline(strm, stu.name, ',') ||
!std::getline(strm, stu.dob, ',') ||
...))
{ // If any read failed, mark the stream as failed so the caller knows.
out.setstate(std::ios_base::failbit);
}
}
return out;
}
Tout d'abord, une astuce mineure, ajoutez un constructeur vide pour la classe pour lancer tous les membres, les entiers {0} et la chaîne {}, ce qui éliminera certains gabages indésirables.
Student::Student() :stdId(0), roll(0), name{}, dob{}, phone{}, address{} {;}
Votre problème majeur provient de la fonction fetchfomrfile () où vous supprimez le tableau Student récupéré, par conséquent, l'appelant a reçu un tableau de données non défini:
Student* fetchFromFile()
{
int i=0;
Student obj;
Student* returnObj = new Student[MAX];
//reading records from file
fin.close();
delete[] returnObj;// <<<< youe deleted
return returnObj; // and return it as undefined
}
Puisque vous êtes capable de calculer la taille du fichier, je suggère dans la fonction appelant:
void search_student(){
// Student* student = fetchFromFile();
Student *student = new Stduent [getFileSize()];
fecchFromFile(student); // use this array in fetch_file
// other things
}
Réécrire fetchFromFile comme:
viod fetchFromFile(Stduent *ss)
{
// read file data to array ss[i];
}