Problem z odczytem obiektów z pliku w C ++

Nov 28 2020

Robię mały projekt w college'u, w którym muszę dodawać, edytować i wyszukiwać rekordy w / z pliku za pomocą koncepcji OOP. Dodawanie do pliku działa dobrze, ale za każdym razem, gdy próbuję odczytać z pliku, jest to drukowane w nieczytelnych tekstach. Oto pełny kod i dane wyjściowe. 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();
}

plik nagłówkowy 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&);
};

Przykładowe wyjście 1

Kiedy dodaję obiekt studenta do pliku

Przykładowe wyjście 2

Czytanie wszystkich rekordów z pliku

Problem1: Pokazywanie wartości id.

Przykładowe wyjście 3

Dodanie kolejnego obiektu do pliku

Przykładowe wyjście 4

Odczytywanie wszystkich obiektów z pliku

Przykładowe wyjście 5

Teraz wrócił i wybrał edycję rekordu

Problem2: Zobacz, jak rekordy są drukowane w nieczytelnej formie.

Dlaczego to się dzieje. Teraz, jeśli zamknę program i uruchomię go ponownie, nadal jest wyświetlany jako nieczytelny tekst. Mam nadzieję, że dostaniesz mój problem. Chcę uzyskać szczegółowe wyjaśnienie na ten temat. Ponadto, jeśli popełniłem inne różne błędy, daj mi znać. Dziękuję Ci!

Odpowiedzi

2 user4581301 Nov 29 2020 at 04:48

Studentjest zbyt skomplikowany do odczytania z niesformatowanymi we / wy takimi jak readi write. Z technicznego punktu widzenia nie można go łatwo skopiować, ponieważ zawiera std::strings i stringnie można go łatwo skopiować.

Najłatwiej jest porzucić readi write. Większość danych to dane w postaci łańcuchów, więc pisz <<i >>przeciążaj Studenti przechowuj wszystko jako tekst.

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

Odczyt danych z powrotem jest nieco trudniejszy

    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;
    } 
1 ytlu Nov 29 2020 at 06:47

Najpierw drobna sztuczka, dodaj pusty konstruktor dla klasy do wszystkich elementów początkowych, liczb całkowitych {0} i string {}, co wyeliminuje niektóre niechciane gabagi.

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

Twój główny problem wynikał z funkcji fetchfomrfile (), w której usuwasz pobraną tablicę Studentów, dlatego wywołujący otrzymał niezdefiniowaną tablicę danych:

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
}

Ponieważ jesteś w stanie obliczyć rozmiar pliku, proponuję w funkcji dzwoniącego:

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

Przepisz fetchFromFile jako:

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