Save and load QList<Class*> to file

3.8k views Asked by At

I have a class ContactData and a class FriendList holding a QList and I overloaded the << / >> operators.


contactdata.h

class ContactData
{
//all public for testing
public:
    ContactData();
    QString m_name;
    QString m_description;
    bool m_online; 
};

QDataStream &operator<<(QDataStream& out, ContactData& contactData);
QDataStream &operator>>(QDataStream& in, ContactData* contactData);

contactdata.cpp

QDataStream &operator<<(QDataStream &out, ContactData& contactData)
{
    out << contactData.m_name;
    out << contactData.m_description;
    return out;
}

QDataStream &operator>>(QDataStream &in, ContactData* contactData)
{
    in >> contactData->m_name;
    in >> contactData->m_description;
    return in;
}

friendlist.h

#include "contactdata.h"
typedef QList<ContactData*> TFriendList;

class FriendList
{
...
public:
TFriendList* m_list;
...
};

QDataStream &operator<<(QDataStream& out, FriendList& list);
QDataStream &operator>>(QDataStream& in, FriendList* list);

friendlist.cpp

QDataStream &operator<<(QDataStream& out, FriendList& list)
{
    for(int i = 0; i < list.size(); i++)
    {
        ContactData contact = *list.at(i);
        out << contact;
    }

    return out;
}

QDataStream &operator>>(QDataStream& in, FriendList* list)
{
    for(int i = 0; i < list->size(); i++)
    {
        ContactData* contact = list->m_list->at(i);
        in >> contact;
    }

    return in;
}

// typedef QList<ContactData*> TFriendList;
private:
    FriendList* m_friendList;

saving function

QString path = "/friendlist.bin";
QFile file(path);

if (file.open(QIODevice::WriteOnly))
{
    QDataStream out(&file);
    out << m_friendList;
    file.close();
}

loading function

QString path = "/friendlist.bin";
QFile file(path);
if(file.exists())
{
  if (file.open(QIODevice::ReadOnly))
  {
     QDataStream in(&file);
     in >> m_friendList;
     file.close();
     qDebug() << "FriendList.size() = " << m_friendList->size();
     }
}

It does save a file in the desired direction, but unfortunately loading gives me an empty list of the size 0. This is where I'm stuck..

Can anyone help?

3

There are 3 answers

0
Adriano Repetti On BEST ANSWER

From your code to rebuild list:

for(int i = 0; i < list->size(); i++) 

Problem is that when you're deserializing into an empty list size() will return 0 (or a value completely unrelated to what you have to read from disk) and anyway you have to read items from stream, it doesn't matter actual list size. Moreoverlist is empty so you have first to create a new element (you can't just call at() because there aren't elements inside). You can write an integer (for example) before items then read it when deserializing:

QDataStream &operator>>(QDataStream& in, FriendList* list)
{
    int count = 0;
    in >> count;

    for(int i = 0; i < count; i++)
    {
        ContactData* contact = new ContactData();
        in >> contact;

        list->m_list->push_back(contact);
    }

    return in;
}

Do not forget to write count in serialization function too. As alternative you may read everything until end of input stream:

QDataStream &operator>>(QDataStream& in, FriendList* list)
{
    int count = 0;
    in >> count;

    while (!in.atEnd())
    {
        ContactData* contact = new ContactData();
        in >> contact;

        list->m_list->push_back(contact);
    }

    return in;
}

To finish check what Kamil said in comment, if you don't have any error during serialization probably it's just a typo but...

0
RobbieE On

You do not need to overload the >> and << operators for QList, they already exist when the left-hand operator is QDataStream

see the documentation

As long as an individual object can serialise and deserialise correctly, all Qt containers should also serialise and deserialise.

0
Dunkelbunt27 On

Thanks to everyone who submitted help, now it works fine to me. For those who are interested, here is what I had to change:

saving function

if (file.open(QIODevice::WriteOnly))
{
    QDataStream out(&file);
    out << *m_friendList;
    file.close();
}

friendlist.cpp

QDataStream &operator>>(QDataStream& in, FriendList* list)
{
    while (!in.atEnd())
    {
        ContactData* contact = new ContactData();
        in >> contact;
        list->m_list->push_back(contact);
    }
    return in;
}