I'm trying to learn how to serialize QMap objects in windowed applications, using this code:
#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
}
The write()
function called by btnSave does indeed save the QMap. I can see the data in snippets.txt. I can see in the debugger that the read()
function, however, doesn't assign anything to the map
variable. What am I missing?
The proper QMap
serialization and deserialization code is the following:
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_5_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_5_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
Build and Run
qmake && make && ./main
Output
QMap(("one", "this is 1")("three", "this is 3")("two", "this is 2"))
You have had several issues:
- Completely neglecting the error codes and strings
This made it really difficult for you to reveal the real issues.
- Using QIODevice::WriteOnly when opening for reading
This was the issue hidden from you without proper error reporting. The problem here is that when you open the file for only writing, any subsequent read operation will yield empty result naturally. It i a bit hidden when doing it through QDataStream
, but if you take a quick look at the QIODevice documentation when you read directly through the QFile instance it becomes a bit more clear what is going on underneath for wrong open mode:
Reads at most maxSize bytes from the device into data, and returns the number of bytes read. If an error occurs, such as when attempting to read from a device opened in WriteOnly mode, this function returns -1.
If you checked the errors, this would have become more clear. To be fair, in your case sharing the file without closing it before the operations could have been acceptable in this simple snippet. In that case, you would have used something like re-seek to the beginning and QIODevice::ReadWrite. Having said that, it is just another way of doing it.
- Incorrect use of qDebug()
This is just a side note, but you were adding spaces explicitly, whereas qDebug() is already doing that for you.
- Needless flushing of the file when serializing.
This is superfluous as it is automatically done when closing the file descriptor through the class destructor.
- Needless closure of the file object
This is automatically done by proper RAII. The desctructor will close it for you if the file is still open. Since you leave the scope of the function, the destructor will be called automatically for your file object as it is constructed on the stack.
May be that's because you are opening the file as WriteOnly
in your read function. The correct form is:
if (!myFile.open(QIODevice::ReadOnly))
{
qDebug() << "Could not read " << filename;
return (map);
}
来源:https://stackoverflow.com/questions/27285889/how-do-you-serialize-a-qmap