Qt源码分析--QSettings

59 篇文章 1 订阅
37 篇文章 1 订阅

定义:

QSettings 类提供与平台无关的持久应用程序设置。

官方例子:

QSettings settings("MySoft", "Star Runner");

settings.setValue("editor/wrapMargin", 68);

int margin = settings.value("editor/wrapMargin").toInt();

1.构造函数

QSettings::QSettings(const QString &organization, const QString &application, QObject *parent)
    : QObject(*QSettingsPrivate::create(NativeFormat, UserScope, organization, application),
              parent)
{
}


QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope,
                                           const QString &organization, const QString &application)
{
    return new QConfFileSettingsPrivate(format, scope, organization, application);
}


QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
                                                   QSettings::Scope scope,
                                                   const QString &organization,
                                                   const QString &application)
    : QSettingsPrivate(format, scope, organization, application),
      nextPosition(0x40000000) // big positive number
{
    initFormat();
    QString org = organization;
    if (org.isEmpty()) {
        setStatus(QSettings::AccessError);
        org = QLatin1String("Unknown Organization");
    }
    QString appFile = org + QDir::separator() + application + extension;
    QString orgFile = org + extension;
    if (scope == QSettings::UserScope) {
        Path userPath = getPath(format, QSettings::UserScope);
        if (!application.isEmpty())
            confFiles.append(QConfFile::fromName(userPath.path + appFile, true));
        confFiles.append(QConfFile::fromName(userPath.path + orgFile, true));
    }
    Path systemPath = getPath(format, QSettings::SystemScope);
#if defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
    // check if the systemPath wasn't overridden by QSettings::setPath()
    if (!systemPath.userDefined) {
        // Note: We can't use QStandardPaths::locateAll() as we need all the
        // possible files (not just the existing ones) and there is no way
        // to exclude user specific (XDG_CONFIG_HOME) directory from the search.
        QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation);
        // remove the QStandardLocation::writableLocation() (XDG_CONFIG_HOME)
        if (!dirs.isEmpty())
            dirs.takeFirst();
        QStringList paths;
        if (!application.isEmpty()) {
            paths.reserve(dirs.size() * 2);
            for (const auto &dir : qAsConst(dirs))
                paths.append(dir + QLatin1Char('/') + appFile);
        } else {
            paths.reserve(dirs.size());
        }
        for (const auto &dir : qAsConst(dirs))
            paths.append(dir + QLatin1Char('/') + orgFile);
        // Note: No check for existence of files is done intentionaly.
        for (const auto &path : qAsConst(paths))
            confFiles.append(QConfFile::fromName(path, false));
    } else
#endif // Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
    {
        if (!application.isEmpty())
            confFiles.append(QConfFile::fromName(systemPath.path + appFile, false));
        confFiles.append(QConfFile::fromName(systemPath.path + orgFile, false));
    }
    initAccess();
}

根据参数进行初始化操作,然后调用initAccess();

void QConfFileSettingsPrivate::initAccess()
{
    if (!confFiles.isEmpty()) {
        if (format > QSettings::IniFormat) {
            if (!readFunc)
                setStatus(QSettings::AccessError);
        }
    }
    sync();       // loads the files the first time
}

void QConfFileSettingsPrivate::sync()
{
    // people probably won't be checking the status a whole lot, so in case of
    // error we just try to go on and make the best of it
    for (auto confFile : qAsConst(confFiles)) {
        QMutexLocker locker(&confFile->mutex);
        syncConfFile(confFile);
    }
}

void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
{
    bool readOnly = confFile->addedKeys.isEmpty() && confFile->removedKeys.isEmpty();
    /*
        We can often optimize the read-only case, if the file on disk
        hasn't changed.
    */
    if (readOnly && confFile->size > 0) {
        QFileInfo fileInfo(confFile->name);
        if (confFile->size == fileInfo.size() && confFile->timeStamp == fileInfo.lastModified())
            return;
    }
    if (!readOnly && !confFile->isWritable()) {
        setStatus(QSettings::AccessError);
        return;
    }
#ifndef QT_BOOTSTRAPPED
    /*
        Use a lockfile in order to protect us against other QSettings instances
        trying to write the same settings at the same time.
        We only need to lock if we are actually writing as only concurrent writes are a problem.
        Concurrent read and write are not a problem because the writing operation is atomic.
    */
    QLockFile lockFile(confFile->name + QLatin1String(".lock"));
    if (!readOnly && !lockFile.lock() && atomicSyncOnly) {
        setStatus(QSettings::AccessError);
        return;
    }
#endif
    /*
        We hold the lock. Let's reread the file if it has changed
        since last time we read it.
    */
    QFileInfo fileInfo(confFile->name);
    bool mustReadFile = true;
    bool createFile = !fileInfo.exists();
    if (!readOnly)
        mustReadFile = (confFile->size != fileInfo.size()
                        || (confFile->size != 0 && confFile->timeStamp != fileInfo.lastModified()));
    if (mustReadFile) {
        confFile->unparsedIniSections.clear();
        confFile->originalKeys.clear();
        QFile file(confFile->name);
        if (!createFile && !file.open(QFile::ReadOnly)) {
            setStatus(QSettings::AccessError);
            return;
        }
        /*
            Files that we can't read (because of permissions or
            because they don't exist) are treated as empty files.
        */
        if (file.isReadable() && file.size() != 0) {
            bool ok = false;
#ifdef Q_OS_MAC
            if (format == QSettings::NativeFormat) {
                QByteArray data = file.readAll();
                ok = readPlistFile(data, &confFile->originalKeys);
            } else
#endif
            if (format <= QSettings::IniFormat) {
                QByteArray data = file.readAll();
                ok = readIniFile(data, &confFile->unparsedIniSections);
            } else if (readFunc) {
                QSettings::SettingsMap tempNewKeys;
                ok = readFunc(file, tempNewKeys);
                if (ok) {
                    QSettings::SettingsMap::const_iterator i = tempNewKeys.constBegin();
                    while (i != tempNewKeys.constEnd()) {
                        confFile->originalKeys.insert(QSettingsKey(i.key(), caseSensitivity),
                                                      i.value());
                        ++i;
                    }
                }
            }
            if (!ok)
                setStatus(QSettings::FormatError);
        }
        confFile->size = fileInfo.size();
        confFile->timeStamp = fileInfo.lastModified();
    }
    /*
        We also need to save the file. We still hold the file lock,
        so everything is under control.
    */
    if (!readOnly) {
        bool ok = false;
        ensureAllSectionsParsed(confFile);
        ParsedSettingsMap mergedKeys = confFile->mergedKeyMap();
#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile)
        QSaveFile sf(confFile->name);
        sf.setDirectWriteFallback(!atomicSyncOnly);
#else
        QFile sf(confFile->name);
#endif
        if (!sf.open(QIODevice::WriteOnly)) {
            setStatus(QSettings::AccessError);
            return;
        }
#ifdef Q_OS_MAC
        if (format == QSettings::NativeFormat) {
            ok = writePlistFile(sf, mergedKeys);
        } else
#endif
        if (format <= QSettings::IniFormat) {
            ok = writeIniFile(sf, mergedKeys);
        } else if (writeFunc) {
            QSettings::SettingsMap tempOriginalKeys;
            ParsedSettingsMap::const_iterator i = mergedKeys.constBegin();
            while (i != mergedKeys.constEnd()) {
                tempOriginalKeys.insert(i.key(), i.value());
                ++i;
            }
            ok = writeFunc(sf, tempOriginalKeys);
        }
#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile)
        if (ok)
            ok = sf.commit();
#endif
        if (ok) {
            confFile->unparsedIniSections.clear();
            confFile->originalKeys = mergedKeys;
            confFile->addedKeys.clear();
            confFile->removedKeys.clear();
            QFileInfo fileInfo(confFile->name);
            confFile->size = fileInfo.size();
            confFile->timeStamp = fileInfo.lastModified();
            // If we have created the file, apply the file perms
            if (createFile) {
                QFile::Permissions perms = fileInfo.permissions() | QFile::ReadOwner | QFile::WriteOwner;
                if (!confFile->userPerms)
                    perms |= QFile::ReadGroup | QFile::ReadOther;
                QFile(confFile->name).setPermissions(perms);
            }
#ifdef Q_OS_WASM
        EM_ASM(
            // Sync sandbox filesystem to persistent database filesystem. See QTBUG-70002
            FS.syncfs(false, function(err) {
            });
        );
#endif
        } else {
            setStatus(QSettings::AccessError);
        }
    }
}

先锁住文件,如果文件格式是ini, 调用readIniFile()函数读取文件。

2.setValue()

void QSettings::setValue(const QString &key, const QVariant &value)
{
    Q_D(QSettings);
    if (key.isEmpty()) {
        qWarning("QSettings::setValue: Empty key passed");
        return;
    }
    QString k = d->actualKey(key);
    d->set(k, value);
    d->requestUpdate();
}

void QConfFileSettingsPrivate::set(const QString &key, const QVariant &value)
{
    if (confFiles.isEmpty())
        return;
    // Note: First config file is always the most specific.
    QConfFile *confFile = confFiles.at(0);
    QSettingsKey theKey(key, caseSensitivity, nextPosition++);
    QMutexLocker locker(&confFile->mutex);
    confFile->removedKeys.remove(theKey);
    confFile->addedKeys.insert(theKey, value);
}

先删除原有的项,然后添加新项。

3.value()

QVariant QSettings::value(const QString &key, const QVariant &defaultValue) const
{
    Q_D(const QSettings);
    if (key.isEmpty()) {
        qWarning("QSettings::value: Empty key passed");
        return QVariant();
    }
    QVariant result = defaultValue;
    QString k = d->actualKey(key);
    d->get(k, &result);
    return result;
}
bool QConfFileSettingsPrivate::get(const QString &key, QVariant *value) const
{
    QSettingsKey theKey(key, caseSensitivity);
    ParsedSettingsMap::const_iterator j;
    bool found = false;
    for (auto confFile : qAsConst(confFiles)) {
        QMutexLocker locker(&confFile->mutex);
        if (!confFile->addedKeys.isEmpty()) {
            j = confFile->addedKeys.constFind(theKey);
            found = (j != confFile->addedKeys.constEnd());
        }
        if (!found) {
            ensureSectionParsed(confFile, theKey);
            j = confFile->originalKeys.constFind(theKey);
            found = (j != confFile->originalKeys.constEnd()
                     && !confFile->removedKeys.contains(theKey));
        }
        if (found && value)
            *value = *j;
        if (found)
            return true;
        if (!fallbacks)
            break;
    }
    return false;
}

代码写的很清楚了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天天进步2015

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值