Я пишу и читаю строковые и целочисленные значения, используя файл 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.
Воу, воу, вы используете файлы .ini или реестр?
С файлами .ini, очевидно, невозможно узнать, какой это был тип, поскольку все это строка. Вы можете попытаться преобразовать вариант в целое число (не использовать canConvert
!) и предположим, что это целое число, если оно конвертируется в единицу.
С реестром, QSettings
будет работать так, как вы ожидаете.
Я действительно не понимаю, в чем проблема. Не использовать .ini
файлы, если вы хотите сохранить информацию о типе. Вы столкнулись бы с точно такими же проблемами, если бы писали код вручную в зависимости от платформы.
Вы можете явно записать строки в кавычках в .ini
файлы и проверять наличие кавычек при чтении их обратно. Если кавычки отсутствуют, вы можете попробовать преобразовать в целое число.
Я решил эту проблему для компонента, который должен сохранять и восстанавливать варианты произвольного типа, не зная, чего ожидают его клиенты. Решение состояло в том, чтобы сохранить вариант 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;
}
wasNull
переменная там из-за этого нигде convert()
:
Предупреждение: По историческим причинам преобразование в нуль
QVariant
приводит к нулевому значению желаемого типа (например, пустая строка дляQString
) и результатfalse
,
В этом случае нам нужно игнорировать вводящее в заблуждение возвращаемое значение и сохранить успешно преобразованный нулевой вариант правильного типа.
Не ясно, что UTF-8 является правильной кодировкой для QMetaType
имена (возможно, предполагается локальный 8-битный?); мои типы все ASCII, поэтому я просто использую toLatin1()
вместо этого, что может быть быстрее. Если бы это было проблемой, я бы использовал QString::fromLatin1
в store()
метод (вместо неявного char*
в QString
конверсия), чтобы обеспечить чистое путешествие туда и обратно.
Если имя типа не найдено, t
будет QMetaType::UnknownType
; это нормально, потому что convert()
затем потерпит неудачу, и мы вернем необращенный вариант (или ноль). Это не очень хорошо, но это ключевой случай, который не случится при нормальном использовании, и моя система восстановится достаточно быстро.
Это очевидно. QSettings
использования QVariant
установить и получить значения.
Пишу, settings.setValue("BBB",222);
значение явно целое число для QVariant
следовательно, результат QVariant::type()
является QVariant::Int
,
При чтении INI-файлы не хранят тип значения, и все является строковым (например, числа также будут считываться как строки). Итак, результат QVariant::type()
является QVariant::String
,
Не заботятся о типах, QVariant
сделаны для прозрачных различий типов, просто конвертируйте их в целые числа (если это невозможно, обрабатывайте это как неверный ввод)
Оказывается, решение было очень простым.
Когда значения записываются в файл INI, тип известен.
Я добавляю к значению «\» STRING прямо перед SetValue
Когда значения считываются обратно из файла INI.
Я проверяю, что строковые типы имеют вышеуказанный постфикс.
Если они это сделают, я отрублю постфикс.
Если они этого не делают, я предполагаю, что они являются целыми числами, а не строками.
Работает как шарм!
Спасибо вам всем и особенно @Kuba Ober за практическую раздачу решения.