Problem while reading objects from file in c++

空扰寡人 提交于 2020-12-15 03:52:16

问题


I am doing a small college project where I have to add, edit and search records in/from file using OOP concept. Adding into file is working fine but whenever I try to read from file it is printing in unreadable texts. Here is full code and output. 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();
}

student.h header file

// 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&);
};

Sample output 1

When I add a student object to file

Sample output 2

Reading all records from file

Problem1: Showing garbage value of id.

Sample output 3

Adding another object to file

Sample output 4

Reading all objects from file

Sample output 5

Now went back and chose to edit record

Problem2: See how the records are printing in unreadable form.

Why is this happening. Now if I close program and run it again then it is still showing in unreadable text. Hope you get my issue. I want to have detailed explanation about this. Also, if I have done other miscellaneous mistakes, please let me know. Thank you!


回答1:


Student is too complicated to read with unformatted IO like read and write. In technical terms, it is not Trivially Copyable because it contain std::strings, and string is not Trivially Copyable.

The easiest thing to do is to abandon read and write. Most of your data is string data, so write << and >> overloads for Student and store everything as text.

    friend std::ostream & operator<<(std::ostream & out, 
                                     const Student & stu) 
    { 
        out << stu.stdId << ',' <<stu.roll << ','<< stu.name... <<'\n'; 
        return out;
    } 

Reading the data back in is a bit trickier

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



回答2:


First, a minor trick, add a empty constructor for class to initailial all members, integers{0}, and string{}, which will elminiate some unwanted gabages.

 Student::Student() :stdId(0), roll(0), name{}, dob{}, phone{}, address{} {;}

Your major problem arised from the function fetchfomrfile() where you delete the fetched Student array, therefore the caller received a undefined data array:

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
}

Since you are able to calculate the size of file, I suggest in the caller function:

void search_student(){
 // Student* student = fetchFromFile();
    Student *student = new Stduent [getFileSize()];
     fecchFromFile(student); // use this array in fetch_file 
  // other things
 }

Rewrite fetchFromFile as :

viod fetchFromFile(Stduent *ss)
{
  // read file data to array ss[i];
}


来源:https://stackoverflow.com/questions/65056564/problem-while-reading-objects-from-file-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!