简体   繁体   中英

(C++) How do i read info from a binary file .dat to be stored in an array of struct?

  • i'm not allowed to use vectors as its not taught in my syllabus

i'm doing an assignment on read/write/store of students assignment marks.

i'm using 2 struct below

struct assessTask
{
    char title [MAX];
    int weight;
    int markUpon;
    float mark;
};

struct subject
{
    char code [MAX];
    char title [MAX];
    int numTask;
    assessTask task [MAX];
    int finalMark;
    UNIGrade grade;
};

A short snip of my write function:(do tell me if this style is correct/wrong)

// run if code is unique        
        strcpy(s[size].code, testcode);
        afile.write (reinterpret_cast <const char *>(&s[size].code), sizeof (s));   

        cin.clear();
        cin.ignore(MAX, '\n');

        cout << "Subject Name: ";
        cin.getline(s[size].title, MAX);
        afile.write (reinterpret_cast <const char *>(&s[size].title), sizeof (s));  

        cout << "No of assessment tasks: ";
        cin >> s[size].numTask;  
        afile.write (reinterpret_cast <const char *>(&s[size].numTask), sizeof (s));

Snippet of whats inside my binary file .dat

so, after i exit from the program, the .dat is stored for future uses. everytime i open the program, it will check for the .dat file, which i can use to query or update through the program

void checkBinary(fstream& afile, const char fileName [], subject s[])
{
    afile.open(fileName, ios::in | ios::binary);

    int g = 0;

    while (afile.read (reinterpret_cast <char *>(&s), sizeof (s)))
    {           
        g++;
    }

    cout << g << endl;

    if (g < 1)
    {
        createBinary (afile, "subject.dat", s); 
    } 
    else
    {
        readBinary (afile, "subject.dat", s);
    }

    afile.close();
}

void createBinary (fstream& afile, const char fileName [], subject s[])
{
    afile.open (fileName, ios::out | ios::binary);

    cout << "Begin the creation of binary file " << fileName << endl;

    afile.write (reinterpret_cast <const char *>(&s), sizeof (s));

    afile.close ();

    cout << "Binary file " << fileName
         << " successfully created"
         << endl;   
}

void readBinary (fstream& afile, const char fileName [], subject s[])
{
    afile.open (fileName, ios::in | ios::binary);

    afile.clear();

    afile.seekg(0, ios::end);
    int size = afile.tellg();
    int noOfRecords = size / sizeof (s);
    afile.seekg(0, ios::beg);   


    while (afile.tellg() < noOfRecords)
    {
        afile.read (reinterpret_cast <char *>(&s), sizeof (s));
        /*
        afile.read (reinterpret_cast <char *>(&s[start].code), sizeof (s));
        afile.read (reinterpret_cast <char *>(&s[start].title), sizeof (s));
        afile.read (reinterpret_cast <char *>(&s[start].numTask), sizeof (s));

        for (int i = 0; i < s[start].numTask; i++)
        {
            afile.read (reinterpret_cast <char *>(&s[start].task[i].title), sizeof (s));
            afile.read (reinterpret_cast <char *>(&s[start].task[i].weight), sizeof (s));
            afile.read (reinterpret_cast <char *>(&s[start].task[i].markUpon), sizeof (s));
        }
        */
    }

    afile.close();
}

for some reason, i have to afile.clear() in the readbinary(), otherwise the bytes returned to me is -1.

The problem i have now is that i need to copy the info from .dat file and store it somewhere so that during consecutive uses of the program, i will still be able to retrieve the data and display it when the s[].code is inputted.

Some things to take note:

  • i'm appending to the .dat, not overwriting
  • i've a query function to read back the data when the user input the subject code
  • i've tried using cout in the readbinary() to see if it reads anything. it just gives me a blank line
  • i heard that i need to store the read info back into a struct of arrays but i dunno how

Still an amateur in C++, i apologise in advance if i do not understand some context

Any help is appreciated. Tks!

A few things:

  1. The reason why you need the afile.clear() is because when you read from the stream, you are advancing where in the file it is reading from. The very first thing you do is you read the whole file... so any further reads are of course going to return no data since you are done reading the file. Until you reset the read location with clear()

  2. This line is buggy:

     while (afile.read (reinterpret_cast <char *>(&s), sizeof (s))) 

sizeof(s) will be equal to sizeof(subject*) and you are reading into junk memory (I think); which leads to issue #3

  1. it is not recommended write things like this:

     void checkBinary(fstream& afile, const char fileName [], subject s[]) 

Because you are losing the size of the array! in C and C++, function parameters aren't arrays (even if they look like them), they are pointers to the first element! And when you pass an array, it "decays" to a pointer.

To make this clear, note that the above line is exactly equal to the following:

void checkBinary(fstream& afile, const char *fileName, subject *s)

It would be better to write your functions like this:

std::vector<subject> checkBinary(const std::string &fileName);

NOTE: the filename is being passed as a std::string and by const reference to avoid unnecessary copies. No need to worry about manually managing the details of a char array and its lifetime if it is allocated on the heap.

Also, The vector of subject objects is returned because this function is producing the subjects by reading them from a file. The vector knows its size, so you never need to bother with things like sizeof

So I might implement one of your functions like this:

std::vector<subject> checkBinary(const std::string &fileName) {

    // why pass the ifstream if you just open/close it in this function
    // do it locally!
    std::ifstream afile(fileName, ios::in | ios::binary);

    subject s;
    std::vector<subject> subjects;

    // read each subject and then add them to the result array!
    while (afile.read (reinterpret_cast <char *>(&s), sizeof (s))) {           
        subjects.push_back(s);
    }

    cout << subject.size() << endl;

    // these will obviously need to be reworked as well to support the 
    // different methodology
    if (subject.empty()) {
        createBinary ("subject.dat", subjects); 
    } else {
        // do we even NEED a readBinary? we just read them above!
    }

    // NOTE: since we made the ifstream locally, no need to close it
    // explicitly! research the concept of RAII and make your code even simpler
    // :-)
    return subjects;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM