Problema ao ler objetos de arquivo em c ++
Estou fazendo um pequeno projeto de faculdade onde tenho que adicionar, editar e pesquisar registros em / de arquivo usando o conceito OOP. Adicionar ao arquivo está funcionando bem, mas sempre que tento ler um arquivo, ele está imprimindo em textos ilegíveis. Aqui está o código completo e a saída. 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();
}
arquivo de cabeçalho 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&);
};
Saída de amostra 1
Quando eu adiciono um objeto de aluno ao arquivo
Resultado de amostra 2
Lendo todos os registros do arquivo
Problema1: Mostrando valor de lixo de id.
Resultado de amostra 3
Adicionando outro objeto ao arquivo
Resultado de amostra 4
Lendo todos os objetos do arquivo
Resultado de amostra 5
Agora voltou e optou por editar o registro
Problema 2: Veja como os registros estão sendo impressos de forma ilegível.
Por que isso está acontecendo. Agora, se eu fechar o programa e executá-lo novamente, ele ainda estará aparecendo em texto ilegível. Espero que você entenda meu problema. Eu quero uma explicação detalhada sobre isso. Além disso, se eu tiver cometido outros erros diversos, por favor, me avise. Obrigado!
Respostas
Student
é muito complicado de ler com IO não formatado como read
e write
. Em termos técnicos, não é Trivialmente Copiável porque contêm std::string
s, e string
não é trivialmente Copiável.
A coisa mais fácil a fazer é abandonar read
e write
. A maioria dos seus dados são dados de string, então escreva <<
e >>
sobrecarregue Student
e armazene tudo como texto.
friend std::ostream & operator<<(std::ostream & out,
const Student & stu)
{
out << stu.stdId << ',' <<stu.roll << ','<< stu.name... <<'\n';
return out;
}
Ler os dados de volta é um pouco mais complicado
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;
}
Primeiro, um truque menor, adicione um construtor vazio para class para inicializar todos os membros, inteiros {0} e string {}, que eliminará alguns gabages indesejados.
Student::Student() :stdId(0), roll(0), name{}, dob{}, phone{}, address{} {;}
Seu principal problema surgiu da função fetchfomrfile () onde você exclui a matriz de Student buscada, portanto, o chamador recebeu uma matriz de dados indefinida:
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
}
Como você pode calcular o tamanho do arquivo, sugiro na função do chamador:
void search_student(){
// Student* student = fetchFromFile();
Student *student = new Stduent [getFileSize()];
fecchFromFile(student); // use this array in fetch_file
// other things
}
Reescreva fetchFromFile como:
viod fetchFromFile(Stduent *ss)
{
// read file data to array ss[i];
}