QSettings не различает строковые значения и значения типа int

Я пишу и читаю строковые и целочисленные значения, используя файл QSettings объект.
Когда я позже попытаюсь прочитать значения из другого процесса, значения будут считаны как строки, а не как 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

Эта проблема присутствует как в Qt 4, так и в Qt 5 в Linux.

2

Решение

Воу, воу, вы используете файлы .ini или реестр?

С файлами .ini, очевидно, невозможно узнать, какой это был тип, поскольку все это строка. Вы можете попытаться преобразовать вариант в целое число (не использовать canConvert!) и предположим, что это целое число, если оно конвертируется в единицу.

С реестром, QSettings будет работать так, как вы ожидаете.

Я действительно не понимаю, в чем проблема. Не использовать .ini файлы, если вы хотите сохранить информацию о типе. Вы столкнулись бы с точно такими же проблемами, если бы писали код вручную в зависимости от платформы.

Вы можете явно записать строки в кавычках в .ini файлы и проверять наличие кавычек при чтении их обратно. Если кавычки отсутствуют, вы можете попробовать преобразовать в целое число.

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,

    В этом случае нам нужно игнорировать вводящее в заблуждение возвращаемое значение и сохранить успешно преобразованный нулевой вариант правильного типа.


  1. Не ясно, что UTF-8 является правильной кодировкой для QMetaType имена (возможно, предполагается локальный 8-битный?); мои типы все ASCII, поэтому я просто использую toLatin1() вместо этого, что может быть быстрее. Если бы это было проблемой, я бы использовал QString::fromLatin1 в store() метод (вместо неявного char* в QString конверсия), чтобы обеспечить чистое путешествие туда и обратно.

    Если имя типа не найдено, t будет QMetaType::UnknownType; это нормально, потому что convert() затем потерпит неудачу, и мы вернем необращенный вариант (или ноль). Это не очень хорошо, но это ключевой случай, который не случится при нормальном использовании, и моя система восстановится достаточно быстро.

1

Это очевидно. QSettings использования QVariant установить и получить значения.

Пишу, settings.setValue("BBB",222); значение явно целое число для QVariant следовательно, результат QVariant::type() является QVariant::Int,

При чтении INI-файлы не хранят тип значения, и все является строковым (например, числа также будут считываться как строки). Итак, результат QVariant::type() является QVariant::String,

Не заботятся о типах, QVariant сделаны для прозрачных различий типов, просто конвертируйте их в целые числа (если это невозможно, обрабатывайте это как неверный ввод)

0

Оказывается, решение было очень простым.

Когда значения записываются в файл INI, тип известен.
Я добавляю к значению «\» STRING прямо перед SetValue

Когда значения считываются обратно из файла INI.
Я проверяю, что строковые типы имеют вышеуказанный постфикс.
Если они это сделают, я отрублю постфикс.
Если они этого не делают, я предполагаю, что они являются целыми числами, а не строками.

Работает как шарм!

Спасибо вам всем и особенно @Kuba Ober за практическую раздачу решения.

0
По вопросам рекламы [email protected]