0

I'm trying to write a C++ code that read from a text file, write all the contents into a binary file, and read a record from the binary file.To hold records, I created a Student class that one of its attribute is enum type.I read from text file successfully, I write the Student records successfully (I check it while debugging), but I have a problem with reading one Nth record from the binary file.Although all attribute are taken successfully, the last attribute whic is enum type is not changed and seems as default even for all records.Although no error exists in the VS 2017, with debugging I recognize that the problem is at binaryRead and readRecord parts (The data in "this" shows the enum attribute as NONE.Also sizeOfOneStudentRecord in seekg, read, readRecord, binaryRead etc. can be not true. I need help friends. The code is given below. I will aprreciate your help.


enum Category { NONE = 0, Honor=1, High_Honor = 2 };
class Student
{
private:
    string name;
    double weight;
    int age;
    Category degree;

public:
    Student();
    Student(string _name, double _weight, int _age, Category _degree);
    Student* txtRead(ifstream& myFile);
    size_t sizeOfOneStudentRecord(Student* a);
    void binaryWrite(fstream& myFile);
    void binaryRead(fstream& myFile);
    void readRecord(fstream& binmyFile, int order);
    friend ostream& operator<<(ostream& output, Student& s) {
    ..
    }
};
Student::Student()
{
    name = "";
    weight = 0.0;
    age = 0;
    degree = NONE;
}
Student::Student(string _name, double _weight, int _age, Category _degree)
{
    name = _name;
    weight = _weight;
    age = _age;
    degree = _degree;
}
size_t Student::sizeOfOneStudentRecord(Student* c) {
    return sizeof(this->name) + sizeof(this->weight) + sizeof(this->age) + sizeof(this->degree);
}
Student* Student::txtRead(ifstream& myFile) {
...

}
void Student::binaryWrite(fstream& myFile) {
    myFile.write((char *)this, sizeOfOneStudentRecord(this));
}
void Student::binaryRead(fstream& myFile) {
    myFile.read((char*)this, sizeOfOneStudentRecord(this));
}
void Student::readRecord(fstream& binmyFile, int order) {
    binmyFile.seekg((order)*sizeOfOneStudentRecord(this));
    binaryRead(binmyFile);
    name = this->name;
    age = this->age;
    weight = this->weight;
    degree = this->degree;
}
int main() {
    Student *StudentArr[20];
    ifstream myFile("Student.txt", ios::in);
    ofstream txtmyFile("newStudentFile.txt", ios::out | ios::trunc);  
    fstream binmyFile("StudentBin.bin", ios::out | ios::in | ios::trunc | ios::binary);

    for (int i = 0; i < 20; i++) {
        StudentArr[i] = new Student();
        StudentArr[i]->txtRead(myFile);
        txtmyFile << *StudentArr[i];
        StudentArr[i]->binaryWrite(binmyFile);
    }
    myFile.close();
    txtmyFile.close();
    Student s1;
    s1.readRecord(binmyFile, 8);
    std::cout << s1 << endl;
    binmyFile.close();
    return 0;}

Denisa
  • 125
  • 4
  • 16
  • 1
    This code will not work. You cannot write non-POD types like `Student` to binary files. Read up on [object serialization](https://stackoverflow.com/questions/523872/how-do-you-serialize-an-object-in-c). The obvious reason why this could never work is that you are consistently writing `sizeof(Student)` bytes to the file. So what happens if that `std::string` member contains 1000 characters? Will those characters magically appear in the file, when you're only writing `sizeof(Student)` bytes? – PaulMcKenzie Apr 02 '20 at 19:18
  • Thanks for your comment @PaulMcKenzie , I will search object serialization but I have to explain that in the main function `std::cout << s1 << endl;` which is created from `Student s1; s1.readRecord(binmyFile, 8); std::cout << s1 << endl;`gives me correct results except one thing:enum type attribute (last attribute), it shows zero for all records. So this makes me think that size calculation can be incorrect or etc. The local data **this** attributes changes with read binary parts except the Category-enum type attribute- it remains default value -0- – Denisa Apr 02 '20 at 19:42
  • 1
    You are probably only getting the results "ok" because the `std::string` is using short-string optimization. If you need proof, try to stick a name with 50 characters in that string. Also, did you read my explanation why it will not work? The `sizeof` is a *compile-time* value. So how is that going to work, since the compiler has no idea how many characters you're going to store in the `std::string`? It's not just about reading up on object serialization -- it's your only choice if you want to save this to a binary file. – PaulMcKenzie Apr 02 '20 at 19:44
  • @PaulMcKenzie thank you friend. I changed all **`sizeOfOneStudentRecord(this) `** to **`sizeOf(Student)`**, the problem is solved all the attributes are correct now, but our lecturer gives us a manual and in this manual he directs us, shows us how sould we implement the part of tasks. He wants from us that a function which calculates size of the processed Student record this function should be used to read binary file and read record functions – Denisa Apr 02 '20 at 20:00
  • maybe I should implement **sizeOfOneStudentRecord** function by **sizeOf(Student)**, this is also a probablity. Anyway, I appreciate it @PaulMcKenzie, thanks again :) – Denisa Apr 02 '20 at 20:04
  • Your professor is wrong, it's just that simple. A type that has a non-POD member **cannot** be serialized in the fashion you are being taught. It has nothing to do with changing `sizeof`. When you write a record to a file, you write the *data* that the record represents, not the raw object bytes as you're doing now. For a `std::string`, you write the characters, not the `std::string` object. If the string has a thousand characters, you have to write those characters to the file, and possibly also the number of characters that were written, so that you can recreate the object when reading. – PaulMcKenzie Apr 02 '20 at 21:06
  • *I changed all sizeOfOneStudentRecord(this) to sizeOf(Student)* -- Sigh, at least I tried. But one more time -- *that is not going to work -- it is wrong*. You are being taught by someone who either does not know the subject, or a `C` programmer who thinks they know C++ well enough to teach it. All of that stuff you're doing now works with `C`, since `C` doesn't have object types like C++. – PaulMcKenzie Apr 02 '20 at 21:09

0 Answers0