Как вы сериализуете QMap?

Я пытаюсь научиться сериализовать объекты QMap в оконных приложениях, используя этот код:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFile>
#include <QString>
#include <QDataStream>
#include <QMap>
#include <QDebug>


void write ()
{
   QString filename = "Z:/snippets.txt";
   QFile myFile (filename);

   if (!myFile.open(QIODevice::WriteOnly))
   {
       qDebug() << "Could not write " << filename;
       return;
   }

   QMap<QString,QString> map;
   map.insert("one","this is 1");
   map.insert("two","this is 2");
   map.insert("three","this is 3");

   QDataStream out (&myFile);
   out.setVersion(QDataStream::Qt_5_3);
   out<<map;

   myFile.flush();
   myFile.close();
}

QMap<QString,QString> read ()
{
    QString filename = "Z:/snippets.txt";
    QFile myFile (filename);
    QMap<QString,QString> map;
    QDataStream in (&myFile);
    in.setVersion(QDataStream::Qt_5_3);

    if (!myFile.open(QIODevice::WriteOnly))
    {
        qDebug() << "Could not read " << filename;
        return (map);
    }

    in >> map;

    myFile.close();
    return(map);
}

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this); 

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_btnSave_clicked()
{
    write();
}

void MainWindow::on_btnLoad_clicked()
{
    QMap<QString,QString> map;
    map = read();
    QMapIterator<QString,QString> i(map);
    //do other stuff
}

Функция write(), вызываемая btnSave, действительно сохраняет QMap. Я вижу данные в snippets.txt. Однако в отладчике я вижу, что функция read() ничего не присваивает переменной map. Что мне не хватает?


person Al C    schedule 04.12.2014    source источник
comment
Почему вы пренебрегаете errorString()? Кроме того, зачем дополнительное место для qDebug()?   -  person lpapp    schedule 04.12.2014
comment
@Ipapp: Потому что я новичок, который не знал о них. Просто прочитайте документацию для QIODevice, из-за вас. Спасибо!   -  person Al C    schedule 04.12.2014
comment
Ты не идиот, чтобы делать ошибки. Мы все так делаем. ;-)   -  person lpapp    schedule 04.12.2014


Ответы (2)


Правильный код сериализации и десериализации QMap выглядит следующим образом:

main.cpp

#include <QString>
#include <QFile>
#include <QMap>
#include <QDataStream>
#include <QDebug>

void write()
{
   QString filename = "snippets.txt";
   QFile myFile(filename);
   if (!myFile.open(QIODevice::WriteOnly))
   {
       qDebug() << "Could not write to file:" << filename << "Error string:" << myFile.errorString();
       return;
   }

   QMap<QString, QString> map;
   map.insert("one", "this is 1");
   map.insert("two", "this is 2");
   map.insert("three", "this is 3");

   QDataStream out(&myFile);
   out.setVersion(QDataStream::Qt
QMap(("one", "this is 1")("three", "this is 3")("two", "this is 2"))
3); out << map; } QMap<QString,QString> read() { QString filename = "snippets.txt"; QFile myFile(filename); QMap<QString, QString> map; QDataStream in(&myFile); in.setVersion(QDataStream::Qt
QMap(("one", "this is 1")("three", "this is 3")("two", "this is 2"))
3); if (!myFile.open(QIODevice::ReadOnly)) { qDebug() << "Could not read the file:" << filename << "Error string:" << myFile.errorString(); return map; } in >> map; return map; } int main() { write(); qDebug() << read(); return 0; }

main.pro

TEMPLATE = app
TARGET = main
QT = core
SOURCES += main.cpp

Построить и запустить

qmake && make && ./main

Выход

QMap(("one", "this is 1")("three", "this is 3")("two", "this is 2"))

У вас было несколько проблем:

Из-за этого вам было очень трудно раскрыть настоящие проблемы.

Это была проблема, скрытая от вас без надлежащего сообщения об ошибках. Проблема здесь в том, что когда вы открываете файл только для записи, любая последующая операция чтения, естественно, даст пустой результат. Это немного скрыто, когда вы делаете это через QDataStream, но если вы бегло взглянете на документация QIODevice, когда вы читаете непосредственно экземпляр QFile, становится немного яснее, что происходит внизу для неправильного режима открытия:

Считывает не более maxSize байтов с устройства в данные и возвращает число прочитанных байтов. Если возникает ошибка, например, при попытке чтения с устройства, открытого в режиме WriteOnly, эта функция возвращает -1.

Если бы вы проверили ошибки, это стало бы более ясным. Справедливости ради, в вашем случае общий доступ к файлу без его закрытия до того, как операции могли бы быть приемлемыми в этом простом фрагменте. В этом случае вы бы использовали что-то вроде повторного поиска в начало и QIODevice::ReadWrite. Сказав это, это просто еще один способ сделать это.

  • Неправильное использование qDebug()

Это просто примечание, но вы явно добавляли пробелы, тогда как qDebug() уже делает это за вас.

  • Излишняя промывка файла при сериализации.

Это лишнее, так как это делается автоматически при закрытии файлового дескриптора через деструктор класса.

  • Бесполезное закрытие файлового объекта

Это автоматически делается правильным RAII. Деструктор закроет его для вас, если файл все еще открыт. Поскольку вы покидаете область действия функции, деструктор будет вызываться автоматически для вашего файлового объекта по мере его создания в стеке.

person lpapp    schedule 04.12.2014
comment
Замечательный поучительный ответ. Спасибо, лпапп! - person Al C; 04.12.2014

Возможно, это потому, что вы открываете файл как WriteOnly в своей функции чтения. Правильная форма:

if (!myFile.open(QIODevice::ReadOnly))
{
    qDebug() << "Could not read " << filename;
    return (map);
}
person Nejat    schedule 04.12.2014