定义:
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;
}
代码写的很清楚了。