QSettings的编码问题(QTBUG15543、QTBUG19552)

晨曦之光 发布于 2012/05/08 10:15
阅读 593
收藏 0

我们在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对象时,发现缓存中有数据,不会再读取文件。于是编码将不会起作用。

如何修复:不太清楚该如何做,或许

  1. 禁用掉这个缓存,这个是最简单的,修改的代码比较少。只要QSettings销毁时不将配置文件内容放入 unusedCache 这个全局静态的QCache对象即可。
  2. 当设置 codecs 的时候,设置一个dirty 标记,这样一来,在使用QSettings时可以强制读取文件。

参考

 


原文链接:http://blog.csdn.net/dbzhang800/article/details/6457716
加载中
返回顶部
顶部