Search code examples
c++ofstream

I need help to properly write the fields of an object into a file in a consecutive manner


I'm working on a project that basically writes into a file the contents of some objects's fields data I've created(one of them being pers1, of the class PERSON);

I've inserted data into the field members of the object pers1, and I opened a file, trying to write the content of those field members(string name, surname and unsigned int age) into the file, using file.write function. It wrote parts of the contents, inbetween alot of garbage. Please help me write the proper code, so that I can write each person details into the file in a consecutive way. Thank you

   #include<iostream>
    #include<string>
    #include<fstream>
    #include <sstream>
    #include <iomanip>
    #include <list>

    class PERSON
    {
        string name;
        string surname;
        unsigned int age;
    public:
        void inputinfo()
        {
            cin>>name;
            cin>>surname;
            cin>>age;
        }
        outputinfo()
        {
            cout<<name;
            cout<<surname;
            cout<<age;
        }
    };

    class STUDENT: public PERSON
    {
        int ID;
        float marks_sum;
        string belonging_class;
    public:
        inputinfo()
        {
            cin>>name;
            cin>>surname;
            cin>>age;
            cin>>ID;
            cin>>marks_sum;
            cin>>belonging_class;
        }
    };

    void writeinfile()
    {
        PERSON pers1;
        ofstream file1
        file1.open("Students.txt", std::ofstream::out | std::ofstream::app);
        pers1.inputinfo();
        file1.write(pers1.c_str(),pers1.length()); // this is the second aproach I've found on internet, but it gives errors;
        file1.write((char*)&pers1, sizeof(pers1)); // this one is puting alot of garbage into the file, alongside fields data.
        fisier.close();
    }

    int main
    {
        int opt1, opt2;
        char option;

        switch(opt1)
        {
        case 1:
            do
            {
                cout<<endl;
                        <<"Choose one of variants"<<"1.Students"<<"2.Teachers"<<"3.Get back to main menu"<<endl;
                cin>>opt2;
                switch(opt2)
                {
                case 1:
                    do
                    {
                        cout<<"Do you wish to introduce a new student(Y/N)?";
                        cin>>option;
                        if(option!='N')
                            writeinfile()
                    } while(option!='N');
                            break;
                    default:
                        cout<<"Incorect!"<<endl;
                    }
                    while(opt2!=3);
                    break;
                case 2: "...."
                    ;
                    break
                case 3: "...."
                    ;
                    break;
                }
            }
        }

I expect clean write of field data into the file, everytime I call the aforementioned function. For example for 1st iteration, when I enter data into the object's field: name : John, surname: Doe, age: 45, I espect to see this data into a single line in the file(and no garbage inbetween).


Solution

  • #include <iostream>
    #include <fstream>
    
    std::ostream& operator<< (std::ostream& os, const PERSON& value )
    {
        // here, you decide how the output format should look like. See below.
        // ...
        return os;
    }
    
    std::istream& operator>> (std::istream& is, PERSON& value )
    {
        // here, you do the reverse of what you chose in operator<<(). See below.
        // ...
        return is;
    }
    

    While you will be able to quickly hack an implementation to those 2 functions, it is worth while thinking of the requirements of what you want to accomplish:

    • Maintenance? What happens to your files in the future when you change your PERSON (e.g. extra fields)? Do you still want to be able to use those old files?
    • Robustness. Will you have to pay attention to localization? What will happen if your first Chinese Student arrives with a Kanji name? Do you need utf8 encoding or alike? Will you encounter "missing values"?
    • Scalability? Will you end up writing your own little data base with your own SQL to later on query for subsets of persons? Will you still be able to read the whole file once it has grown beyond expectations? Will new files with other data arrive and later there will be the need to associate them? (OUTER JOIN, INNER JOIN,...)

    As you can see from this short and certainly incomplete list, you are at a cross road here: Use database instead? Use a standard serialization format like XML or JSON or protocol buffers or FastNProto or whatever is fashionable today? Or just go ahead and do your own thing as it is all a quick and dirty thing anyway?

    Now, to the practical things:

    Inside your operator<<, you can "dump" your elements like this (sticking to what you wrote in the question):

    os << "name: " << value.name.c_str() 
       << ", surname: " << value.surname.c_str() 
       << ", age: " << value.age 
       << std::endl;
    

    And to read it back in, you implement the operator>> accordingly.

    std::string tag;
    is >> tag; // optionally make sure it is "name:"
    is >> value.name;
    // ... (The commas might need some fiddling... well you wanted help not a full solution...)
    

    Then, all you need to do is test it, e.g. using a string stream, serialize a person, read it into another instance and compare. And you should be done ;)