【问题标题】:How do you serialize a QMap?你如何序列化 QMap?
【发布时间】:2014-12-04 03:42:16
【问题描述】:

我正在尝试学习如何使用以下代码在窗口应用程序中序列化 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
}

btnSave 调用的write() 函数确实保存了QMap。我可以在 sn-ps.txt 中看到数据。但是,我可以在调试器中看到read() 函数没有为map 变量分配任何内容。我错过了什么?

【问题讨论】:

  • 为什么你忽略了errorString()s?另外,为什么要为 qDebug() 留出额外的空间?
  • @Ipapp:因为我是一个不了解它们的新手。不过,因为你,请阅读 QIODevice 的文档。谢谢!
  • 你不是犯错误的白痴。我们都这样做。 ;-)

标签: c++ qt qtcore qfile qmap


【解决方案1】:

正确的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_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

构建并运行

qmake && make && ./main

输出

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

您遇到了几个问题:

这让你很难揭露真正的问题。

这是在没有正确报告错误的情况下对您隐藏的问题。这里的问题是,当您打开文件仅用于写入时,任何后续读取操作都会自然产生空结果。通过QDataStream 执行此操作时,它有点隐藏,但如果您快速查看QIODevice documentation,当您直接通过 QFile 实例读取时,会更清楚在错误的打开模式下发生了什么:

从设备中最多读取 maxSize 个字节到数据中,并返回读取的字节数。如果发生错误,例如尝试从以 WriteOnly 模式打开的设备进行读取时,此函数将返回 -1。

如果您检查了错误,这将变得更加清晰。公平地说,在您的情况下,在这个简单的 sn-p 操作可以接受之前共享文件而不关闭它。在这种情况下,您可能会使用重新搜索开头和 QIODevice::ReadWrite 之类的东西。话虽如此,这只是另一种方式。

  • qDebug() 使用不正确

这只是一个旁注,但您明确添加了空格,而 qDebug() 已经为您这样做了。

  • 序列化时不必要地刷新文件。

这是多余的,因为它是在通过类析构函数关闭文件描述符时自动完成的。

  • 文件对象的不必要的关闭

这是由适当的 RAII 自动完成的。如果文件仍然打开,析构函数将为您关闭它。由于您离开了函数的范围,因此在堆栈上构造文件对象时,将自动为您的文件对象调用析构函数。

【讨论】:

  • 非常有教育意义的答案。谢谢你,lpapp!
【解决方案2】:

可能是因为您在读取功能中以WriteOnly 的身份打开文件。正确的形式是:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    • 1970-01-01
    • 2021-07-28
    • 1970-01-01
    • 2020-02-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多