2

我正在使用文件支持的QSettings对象写入和读取字符串和 int 值。当我后来尝试从不同的进程中读取值时,这些值被读取为字符串而不是 int。

这是我用来写值的代码:

QSettings settings("TestQSettings.ini", QSettings::IniFormat);
settings.setValue("AAA",QString("111"));
settings.setValue("BBB",222);

这是创建的文件:

[General]
AAA=111
BBB=222

这是我用来读取值的代码:

QVariant qvar = settings.value("AAA");
std::cout << "AAA type " << qvar.type() << std::endl;
qvar = settings.value("BBB");
std::cout << "BBB type " << qvar.type() << std::endl;

如果我从同一进程运行此代码:

AAA type 10
BBB type 2

如果我从不同的进程运行此代码:

AAA type 10
BBB type 10

我知道可以在读取类型后转换类型。不幸的是,此解决方案将需要修改我不想修改的 Windows 遗留跨平台代码,例如多次调用RegQueryValueEx().

是否可以存储和读取字符串和整数的类型信息?

例如,字符串会有引号"",而整数不会:

[General]
AAA="111"
BBB=222

这个问题在 Linux 上的 Qt 4 和 Qt 5 上都存在。

4

3 回答 3

1

哇哇哇,您使用的是 .ini 文件还是注册表?

对于 .ini 文件,显然不可能知道类型是什么,因为它都是一个字符串。您可以尝试将变体转换为整数(不要使用canConvert!),如果转换为整数,则假定它是整数。

使用注册表,QSettings将按您的预期工作。

我真的不明白问题是什么。.ini如果您希望保留类型信息,请不要使用文件。如果您以依赖于平台的方式手动编写代码,您将面临完全相同的问题。

您可以将带引号的字符串显式写入.ini文件,并在读取它们时检查是否存在引号。如果引号不存在,您可以尝试转换为整数。

于 2013-10-14T11:29:12.123 回答
1

我为一个需要保存和恢复任意类型的变体的组件解决了这个问题,而不知道它的客户期望什么。解决方案是将变体存储在typeName()每个值旁边:

void store(QSettings& settings, const QString& key, const QVariant& value)
{
    settings.setValue(key+"value", value);
    settings.setValue(key+"type", value.typeName());
}

回读时,我们还会在返回之前读取类型名称和convert()变体(如果它还不是正确的类型)。

QVariant retrieve(const QSettings& settings, const QString& key)
{
    auto value = settings.value(key+"value");
    const auto typeName = settings.value(key+"type").toString();

    const bool wasNull = value.isNull();                         // NOTE 1
    const auto t = QMetaType::type(typeName.toUtf8());           // NOTE 2

    if (value.userType() != t && !value.convert(t) && !wasNull) {
        // restore value that was cleared by the failed convert()
        value = settings.value(key+"value");
        qWarning() << "Failed to convert value" << value << "to" << typeName;
    }

    return value;
}

笔记

  1. wasNull变量在那里是因为这个小问题convert()

    警告:由于历史原因,转换QVariant空值会导致所需类型的空值(例如,空字符串QString)和false.

    在这种情况下,我们需要忽略误导性的返回值,并保持正确类型的成功转换的 null 变体。


  1. 目前尚不清楚 UTF-8 是否是QMetaType名称的正确编码(可能假定为本地 8 位?);我的类型都是 ASCII,所以我只是使用toLatin1()它,这可能会更快。如果这是一个问题,我会QString::fromLatin1store()方法中使用(而不是隐式char*转换QString),以确保干净的往返。

    如果找不到类型名称,t将为QMetaType::UnknownType; 没关系,因为convert()这样会失败,我们将返回未转换的变体(或 null)。这不是很好,但这是一个在正常使用中不会发生的极端情况,我的系统会很快恢复。

于 2016-08-25T14:36:24.830 回答
0

原来解决方案非常简单。

当值被写入 INI 文件时,类型是已知的。我在 SetValue 之前附加到值 "\"STRING

从 INI 文件读回值时。我验证字符串类型是否具有上述后缀。如果他们这样做,我把后缀砍掉。如果不是,我假设它们是整数而不是字符串。

奇迹般有效!

感谢大家,尤其是 @Kuba Ober,感谢您实际分发了解决方案。

于 2013-10-15T06:09:54.997 回答