我们在QSettings 与中文 一文中认识了QSettings在Qt4.5中引入的setIniCodec成员函数。
这是一个挺不错的函数,估计解决了不少人的中文(我自己几乎不在里面用中文,感受不是太深)。
这两天看Qt的bugreport,发现这个看似无害的便利函数还是直接导致了一些 bug:
QTBUG15543
是一个这样的问题:
- 一个长度为256的QByteArray对象(存放"/x0/x1/x2.../x255")
- 将该对象通过设置了编码的QSettings写入ini文件后,内容不对!
- 当然更无法正确读入了
- 如果不设置编码的话,写入和读出的内容是一致的(也就是工作正常)。
bug提交者给出的代码如下:
#include <QtCore/QCoreApplication>
#include <QSettings>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
{
QSettings set("settings.ini",QSettings::IniFormat,0);
set.setIniCodec("cp1251");
QByteArray ba;
ba.resize(256);
for(int i=0;i<ba.size();i++){
ba[i]=i;
}
set.setValue("array",ba);
}
{
QSettings set("settings.ini",QSettings::IniFormat,0);
set.setIniCodec("cp1251");
QByteArray ba=set.value("array").toByteArray();
qDebug()<<"size="<<ba.size();
for(int i=0;i<ba.size();i++){
if((uchar)ba.at(i)!=i){
qDebug()<<"Error: "<<i<<"!="<<(uchar)ba.at(i);
break;
}
}
}
return 0;
}
原因
我们在QSettings 与中文 一文中涉及到这部分内容。
-
QSettings 的核心是 一个QMap<QString, QVariant> ,key是一个QString,value是QVariant类型
- 将value写入文件的过程分两步
- 将 QVariant 变成 QString 或 QStringList
- 将字符串和字符串列表序列化(字符转义、解码等)得到QByteArray字节流
回头看这个bug:
-
QByteArray 对象存放在QVariant中,第一步先变成QString:@ByteArray(.....)
-
括号内是QByteArray的真实内容"/x0/x1/x2.../x255" 对应的字符串。其实这是通过QString::fromLatin1()实现的
-
- 将该字符串转义并采用指定的codec进行编码
-
问题出来了:cp1251 无法对U+128U+129 等unicode字符进行解码,于是问号被写入了ini文件。
-
bug的修复:
- 这个应该还算比较简单,只要保证对于QByteArray不进行编码即可(当然,对于其他一些自定义的类型,会变成字符串Variant(...),也不能进行编码)
QTBUG-19552
是这样一个问题:
- 用未设置codec的QSettings读入一个ini文件
- 销毁该 QSettings 对象
- 用设置了codec的QSettings重现读入该ini文件
- 设置的编码不起作用
bug 提交者给出的代码如下
#include <QtCore/QCoreApplication>
#include <QtCore/QSettings>
#include <QtCore/QString>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QString v;
{
QSettings settings("test1.ini", QSettings::IniFormat);
v = settings.value("lang").toString();
}
QSettings settings1("test1.ini", QSettings::IniFormat);
settings1.setIniCodec("UTF-8");
QString v1 = settings1.value("lang").toString();
return 0;
}
原因
QSettings 应该是处于性能上的考虑,会对读入的ini文件内容进行缓存。
这个bug产生的原因是:
- 上一个对象销毁时,读入的ini的内容被缓存了
- 新创建QSettings对象时,发现缓存中有数据,不会再读取文件。于是编码将不会起作用。
如何修复:不太清楚该如何做,或许
- 禁用掉这个缓存,这个是最简单的,修改的代码比较少。只要QSettings销毁时不将配置文件内容放入 unusedCache 这个全局静态的QCache对象即可。
- 当设置 codecs 的时候,设置一个dirty 标记,这样一来,在使用QSettings时可以强制读取文件。
参考

本文探讨了Qt中QSettings组件在处理中文和其他特殊字符时遇到的问题,并提供了两个具体案例分析及解决方案。
3763

被折叠的 条评论
为什么被折叠?



