QSettings::allKeys()

2025-05-27

QSettings::allKeys() とは

QSettings クラスは、Qtアプリケーションの設定を永続的に保存および読み込むためのクラスです。OSのレジストリ(Windows)、INIファイル(Windows/Unix)、プロパティリスト(macOS)など、プラットフォームに依存しない方法で設定を扱うことができます。

QSettings::allKeys() メソッドは、この QSettings オブジェクトが現在アクセスできるすべての設定キー(サブキーを含む)のリストを QStringList 型で返します。

使い方

allKeys() メソッドは、設定ファイルやレジストリに保存されているすべての設定項目をプログラムで列挙したい場合によく使用されます。例えば、ユーザーが設定を変更できる画面で、現在保存されている設定項目をすべて表示したい場合などに便利です。

以下にC++での使用例を示します。

#include <QCoreApplication>
#include <QSettings>
#include <QStringList>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    // アプリケーション名と組織名をQSettingsに認識させる
    QCoreApplication::setOrganizationName("MyCompany");
    QCoreApplication::setApplicationName("MyApplication");

    QSettings settings; // QSettingsオブジェクトを作成

    // サンプルとしていくつかの設定値を保存
    settings.setValue("user/name", "太郎");
    settings.setValue("user/age", 30);
    settings.setValue("display/theme", "dark");
    settings.setValue("display/fontSize", 12);

    // すべてのキーを取得
    QStringList allKeys = settings.allKeys();

    qDebug() << "すべての設定キー:";
    for (const QString &key : allKeys) {
        qDebug() << "  " << key << " = " << settings.value(key).toString();
    }

    return 0;
}

このコードを実行すると、次のような出力が得られるはずです(設定が実際に保存される場所はOSによって異なります)。

すべての設定キー:
   "user/name" = "太郎"
   "user/age" = "30"
   "display/theme" = "dark"
   "display/fontSize" = "12"
  • パフォーマンス
    大量の設定キーがある場合、allKeys() を呼び出すと一時的にパフォーマンスに影響を与える可能性があります。ただし、通常の設定数であればほとんど問題になりません。
  • プラットフォーム差
    キーの大文字・小文字の区別は、使用しているプラットフォームの設定ストレージメカニズムによって異なります。WindowsのレジストリやINIファイルは通常大文字・小文字を区別しませんが、macOSのCarbon Preferences APIは区別します。移植性の問題を避けるため、キー名には常に同じ大文字・小文字の区別を使用することが推奨されます。
  • 読み取り専用
    allKeys() は設定キーのリストを返しますが、その値は QSettings::value() を使用して別途取得する必要があります。
  • 現在のグループ
    QSettings::beginGroup() を使用してグループに入っている場合、allKeys() はそのグループ内のキーのみを返します。グループ全体(ルート)のキーを取得したい場合は、beginGroup() の呼び出し前に allKeys() を呼び出すか、endGroup() でルートに戻る必要があります。


QSettings::allKeys() 自体は、設定キーのリストを返す単純なメソッドですが、それを取り巻く環境や使い方によって、意図しない結果や問題が発生することがあります。

想定したキーが返されない(空のリスト、または一部のキーしか返されない)

原因

  • キーの大文字・小文字の不一致
    プラットフォームによっては(特にmacOSのCarbon API)、キーの大文字・小文字を区別します。setValue() で保存したキーと、allKeys() で得られるキー(または取得しようとしているキー)の大文字・小文字が一致しない場合、問題が生じることがあります。
  • アクセス権限の問題
    設定ファイルやレジストリへの書き込み/読み取り権限がない場合、設定が保存されなかったり、読み込めなかったりします。
  • 異なるストレージ形式
    開発中にINIファイルを使用し、デプロイ時にレジストリ(Windows)を使用するなど、ストレージ形式が異なっている場合、期待するキーが見つからないことがあります。
  • beginGroup() の影響
    QSettings::beginGroup() を呼び出した後で allKeys() を呼び出すと、そのグループ内のキーしか返されません。ルートレベルのキーを取得したい場合は、beginGroup() の呼び出し前に allKeys() を呼び出すか、endGroup() でルートに戻る必要があります。
  • 誤った QSettings オブジェクトを使用している
    アプリケーション名や組織名が QSettings オブジェクトを作成したときと異なっている場合、別の設定ファイルやレジストリパスを参照してしまい、期待するキーが見つからないことがあります。
  • 設定がまだ保存されていない
    最も一般的な原因です。QSettings に設定値を保存(setValue())していない場合、allKeys() は何も返しません。

トラブルシューティング

  • 権限を確認する
    アプリケーションを実行しているユーザーに、設定ファイルまたはレジストリパスへの読み書き権限があることを確認します。
  • デバッグ出力を使用する
    qDebug() を使って、allKeys() が何を返しているのかを確認します。
    QSettings settings;
    QStringList keys = settings.allKeys();
    qDebug() << "取得されたキー:" << keys;
    
  • 設定ファイルの場所を確認する
    • Windows: レジストリ(HKEY_CURRENT_USER\Software\組織名\アプリケーション名)またはINIファイル。
    • macOS: ~/Library/Preferences/組織名.アプリケーション名.plist
    • Linux: ~/.config/組織名/アプリケーション名.conf またはINIファイル。 直接その場所を見に行き、設定が実際に保存されているか確認します。
  • beginGroup() の使用状況を確認する
    QSettings settings;
    // ルートのキーを取得したい場合
    QStringList rootKeys = settings.allKeys();
    
    settings.beginGroup("MyGroup");
    // "MyGroup" 内のキーを取得したい場合
    QStringList groupKeys = settings.allKeys();
    settings.endGroup();
    
  • アプリケーション名と組織名を統一する
    QCoreApplication::setOrganizationName()QCoreApplication::setApplicationName() は、QSettings オブジェクトが参照する設定の場所を決定します。これらが一貫していることを確認してください。
    // 必ずQSettingsオブジェクトを作成する前に設定
    QCoreApplication::setOrganizationName("MyCompany");
    QCoreApplication::setApplicationName("MyApplication");
    
    QSettings settings; // これで正しい設定場所を参照
    
  • QSettings::setValue() で設定値を保存したか確認する
    QSettings オブジェクトを作成し、値を設定した後、アプリケーションを正常に終了させるか、settings.sync() を明示的に呼び出して設定をディスクに書き込む必要があります。

パフォーマンスの問題

原因

  • 非常に多数のキー
    QSettings に数千、数万といった非常に大量のキーが保存されている場合、allKeys() の呼び出しが遅くなる可能性があります。QSettings は設定を一度に読み込むため、キーの数が多いとオーバーヘッドが大きくなります。

トラブルシューティング

  • グループ化を活用する
    特定の機能に関連するキーをグループ化し、beginGroup() を使用して必要なグループ内のみのキーを取得することで、処理対象のキーの数を減らせます。
  • 必要なときだけ allKeys() を呼び出す
    アプリケーションの起動時など、必要なときだけキーを列挙し、キャッシュするなどして頻繁な呼び出しを避けます。

設定の同期に関する問題

原因

  • sync() の不足
    QSettings::setValue() を呼び出した後、設定がすぐにディスクに書き込まれるとは限りません。アプリケーションの終了時に自動的に同期されますが、それより前に確実に書き込みたい場合は QSettings::sync() を明示的に呼び出す必要があります。sync() が呼び出されていない状態で別のプロセスが allKeys() を呼び出すと、最新の設定が反映されていない可能性があります。

トラブルシューティング

  • QSettings::sync() を適切に呼び出す
    特に、設定を保存した直後に別のプロセスでその設定を読み込むようなシナリオでは、sync() の呼び出しが重要です。
    settings.setValue("some/key", "value");
    settings.sync(); // これで確実にディスクに書き込まれる
    

クロスプラットフォームでの問題

原因

  • プラットフォームごとの動作の違い
    QSettings はプラットフォームのネイティブな設定メカニズムを利用するため、Windows、macOS、Linux で設定の保存場所やキーの扱いに微妙な違いがあります。特に、大文字・小文字の区別は注意が必要です。
  • 設定のストレージ形式の明示
    必要であれば、QSettings::NativeFormat の代わりに QSettings::IniFormat を明示的に指定して、INIファイルとして設定を管理することもできます。これにより、プラットフォームによる違いをある程度吸収できますが、ネイティブな統合は失われます。
    QSettings settings(QSettings::IniFormat, QSettings::UserScope, "MyCompany", "MyApplication");
    
  • テストの実施
    異なるOS環境でテストを行い、期待通りに動作するか確認します。
  • キー名の一貫性
    キー名には常に同じ大文字・小文字の区別を使用し、プラットフォーム間の差異に依存しないようにします。


QSettings::allKeys() は、アプリケーションの設定に保存されているすべてのキーを取得するために使用されます。以下にいくつかの具体的な使用例を示します。

基本的な使用法:すべての設定キーとその値を列挙する

この例では、いくつかの設定値を保存し、その後 allKeys() を使って保存されているすべてのキーを列挙し、それぞれの値を出力します。

#include <QCoreApplication>
#include <QSettings>
#include <QStringList>
#include <QDebug>
#include <QVariant> // QVariantを使うために必要

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    // QSettingsが参照する設定の場所を特定するために、組織名とアプリケーション名を設定します。
    // これはQSettingsオブジェクトを作成する前に呼び出す必要があります。
    QCoreApplication::setOrganizationName("MyCompany");
    QCoreApplication::setApplicationName("MyApplication");

    // QSettingsオブジェクトを作成します。
    // コンストラクタに引数を渡さない場合、setOrganizationNameとsetApplicationNameで設定された情報を使用します。
    QSettings settings;

    // いくつかの設定値を保存します
    settings.setValue("user/name", "田中 太郎");
    settings.setValue("user/age", 30);
    settings.setValue("app/theme", "dark");
    settings.setValue("app/language", "ja_JP");
    settings.setValue("printer/default", "OfficePrinter");
    settings.setValue("printer/copies", 1);
    settings.setValue("last_session/geometry", QRect(100, 100, 800, 600)); // QRectもQVariantで保存可能

    // 設定が確実にディスクに書き込まれるように同期します(通常はアプリ終了時に自動的に行われますが、明示的に行うこともできます)
    settings.sync();

    qDebug() << "--- 保存されているすべての設定キーと値 ---";

    // allKeys() を使ってすべてのキーのリストを取得します
    QStringList allKeys = settings.allKeys();

    // 取得したキーを一つずつ処理します
    for (const QString &key : allKeys) {
        QVariant value = settings.value(key); // キーに対応する値を取得します
        qDebug() << "キー:" << key << ", 値:" << value;
    }

    qDebug() << "--------------------------------------";

    return app.exec();
}

出力例

--- 保存されているすべての設定キーと値 ---
キー: "app/language", 値: QVariant(QString, "ja_JP")
キー: "app/theme", 値: QVariant(QString, "dark")
キー: "last_session/geometry", 値: QVariant(QRect, QRect(100,100,800,600))
キー: "printer/copies", 値: QVariant(int, 1)
キー: "printer/default", 値: QVariant(QString, "OfficePrinter")
キー: "user/age", 値: QVariant(int, 30)
キー: "user/name", 値: QVariant(QString, "田中 太郎")
--------------------------------------

解説

  • settings.value(key) で各キーに対応する QVariant の値を取得し、それを表示しています。QVariant は様々なデータ型を保持できる便利なクラスです。
  • settings.allKeys() は、保存されているキーのリストを QStringList で返します。
  • settings.sync() は、変更をディスクに書き込むことを保証します。
  • settings.setValue() で様々な型のデータをキーと関連付けて保存できます。QVariant が内部的に型の変換を処理します。
  • QCoreApplication::setOrganizationName()QCoreApplication::setApplicationName() は、設定がどこに保存されるかを決定するために重要です。これらを呼び出さない場合、QSettings はデフォルトの場所を使用しようとしますが、推奨されません。

グループ内のキーを列挙する

QSettings では、設定を階層的にグループ化できます。beginGroup() を使用してグループに入ると、allKeys() はそのグループ内のキーのみを返します。

#include <QCoreApplication>
#include <QSettings>
#include <QStringList>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QCoreApplication::setOrganizationName("MyCompany");
    QCoreApplication::setApplicationName("MyApplication");

    QSettings settings;

    // ルートレベルに設定
    settings.setValue("global/setting1", "valueA");
    settings.setValue("global/setting2", "valueB");

    // "user" グループに設定
    settings.beginGroup("user");
    settings.setValue("name", "佐藤 花子");
    settings.setValue("email", "[email protected]");
    settings.endGroup(); // "user" グループを終了

    // "network" グループに設定
    settings.beginGroup("network");
    settings.setValue("proxy/enabled", true);
    settings.setValue("proxy/address", "192.168.1.1");
    settings.endGroup(); // "network" グループを終了

    settings.sync();

    qDebug() << "--- ルートレベルのすべての設定キー ---";
    QStringList rootKeys = settings.allKeys(); // beginGroup() の外で呼び出すとルートのキーを取得
    for (const QString &key : rootKeys) {
        qDebug() << "  " << key;
    }

    qDebug() << "\n--- 'user' グループ内のすべての設定キー ---";
    settings.beginGroup("user");
    QStringList userGroupKeys = settings.allKeys(); // "user" グループ内でのallKeys()
    for (const QString &key : userGroupKeys) {
        qDebug() << "  " << key; // キーはグループ名なしで返されます
    }
    settings.endGroup();

    qDebug() << "\n--- 'network' グループ内のすべての設定キー ---";
    settings.beginGroup("network");
    QStringList networkGroupKeys = settings.allKeys(); // "network" グループ内でのallKeys()
    for (const QString &key : networkGroupKeys) {
        qDebug() << "  " << key;
    }
    settings.endGroup();

    return app.exec();
}

出力例

--- ルートレベルのすべての設定キー ---
   "app/language"
   "app/theme"
   "global/setting1"
   "global/setting2"
   "last_session/geometry"
   "network/proxy/address"
   "network/proxy/enabled"
   "printer/copies"
   "printer/default"
   "user/email"
   "user/name"

--- 'user' グループ内のすべての設定キー ---
   "email"
   "name"

--- 'network' グループ内のすべての設定キー ---
   "proxy/address"
   "proxy/enabled"

解説

  • グループ内のキーは、グループ名を除いた形で返されます。例えば、"user/name" は "name" として返されます。
  • allKeys() を呼び出す前に beginGroup("user")beginGroup("network") を呼び出すことで、そのグループ内のキーのみが返されます。

QSettings::childKeys() との違い

QSettings には childKeys() という似たようなメソッドもありますが、allKeys() とは動作が異なります。

  • childKeys(): カレントグループの直下にあるトップレベルのキーのみを返します(サブグループ内のキーは含みません)。
  • allKeys(): カレントグループ(およびサブグループ)内のすべてのキーを、完全なパスで返します。
#include <QCoreApplication>
#include <QSettings>
#include <QStringList>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QCoreApplication::setOrganizationName("MyCompany");
    QCoreApplication::setApplicationName("MyApplication");

    QSettings settings;

    settings.setValue("section1/key1", "value1");
    settings.setValue("section1/subsectionA/keyA", "valueA");
    settings.setValue("section1/subsectionA/keyB", "valueB");
    settings.setValue("section2/key2", "value2");
    settings.setValue("top_level_key", "top_value");

    settings.sync();

    qDebug() << "--- ルートレベルでの allKeys() ---";
    QStringList allKeysRoot = settings.allKeys();
    for (const QString &key : allKeysRoot) {
        qDebug() << "  " << key;
    }

    qDebug() << "\n--- ルートレベルでの childKeys() ---";
    QStringList childKeysRoot = settings.childKeys();
    for (const QString &key : childKeysRoot) {
        qDebug() << "  " << key;
    }

    settings.beginGroup("section1");
    qDebug() << "\n--- 'section1' グループでの allKeys() ---";
    QStringList allKeysSection1 = settings.allKeys();
    for (const QString &key : allKeysSection1) {
        qDebug() << "  " << key;
    }

    qDebug() << "\n--- 'section1' グループでの childKeys() ---";
    QStringList childKeysSection1 = settings.childKeys();
    for (const QString &key : childKeysSection1) {
        qDebug() << "  " << key;
    }
    settings.endGroup();

    return app.exec();
}

出力例

--- ルートレベルでの allKeys() ---
   "section1/key1"
   "section1/subsectionA/keyA"
   "section1/subsectionA/keyB"
   "section2/key2"
   "top_level_key"

--- ルートレベルでの childKeys() ---
   "section1/key1"
   "section2/key2"
   "top_level_key"

--- 'section1' グループでの allKeys() ---
   "key1"
   "subsectionA/keyA"
   "subsectionA/keyB"

--- 'section1' グループでの childKeys() ---
   "key1"
  • section1 グループに入ると、allKeys() は "key1" と "subsectionA/keyA"、"subsectionA/keyB" のように、そのグループ内のすべてのキーを返します。一方、childKeys() は "key1" のように、section1 の直下にあるキーのみを返します。
  • ルートレベルでは、allKeys() はすべての階層のキーを返しますが、childKeys() は "section1/key1"、"section2/key2"、"top_level_key" のように、直接ルートにあるキーのみを返します。


QSettings::childKeys() と QSettings::childGroups() を組み合わせた再帰的な走査

allKeys() は、現在のグループとすべてのサブグループのキーを一度に返しますが、childKeys() は現在のグループ直下のキーのみを、childGroups() は現在のグループ直下のサブグループ名を返します。これらのメソッドを再帰的に組み合わせることで、独自のキー列挙ロジックを構築できます。

ユースケース

  • デバッグ目的で、設定の構造を詳細に表示したい場合。
  • キーの列挙中に特定の条件でフィルタリングや処理を行いたい場合。
  • 特定の深さまでのキーのみを列挙したい場合。
  • キーを階層構造で処理したい場合。

コード例

#include <QCoreApplication>
#include <QSettings>
#include <QStringList>
#include <QDebug>

// 設定キーとグループを再帰的に走査するヘルパー関数
void listSettingsRecursively(QSettings &settings, const QString &currentPath = "") {
    // 現在のグループ内のキーを列挙
    QStringList keys = settings.childKeys();
    for (const QString &key : keys) {
        qDebug() << "  " << currentPath + key << " = " << settings.value(key).toString();
    }

    // 現在のグループ内のサブグループを列挙し、再帰的に処理
    QStringList groups = settings.childGroups();
    for (const QString &group : groups) {
        qDebug() << "グループ: " << currentPath + group + "/";
        settings.beginGroup(group); // サブグループに入る
        listSettingsRecursively(settings, currentPath + group + "/"); // 再帰呼び出し
        settings.endGroup();   // サブグループから出る
    }
}

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QCoreApplication::setOrganizationName("MyCompany");
    QCoreApplication::setApplicationName("MyApplication");

    QSettings settings;

    // サンプル設定を保存
    settings.setValue("general/language", "en_US");
    settings.setValue("general/theme", "light");
    settings.setValue("user/profile/name", "John Doe");
    settings.setValue("user/profile/email", "[email protected]");
    settings.setValue("network/proxy/enabled", true);
    settings.setValue("network/proxy/address", "127.0.0.1");

    settings.sync();

    qDebug() << "--- 設定の再帰的なリスト ---";
    listSettingsRecursively(settings);
    qDebug() << "---------------------------";

    return app.exec();
}

出力例

--- 設定の再帰的なリスト ---
   "general/language" = "en_US"
   "general/theme" = "light"
グループ:  network/
   "network/proxy/address" = "127.0.0.1"
   "network/proxy/enabled" = "true"
グループ:  user/
グループ:  user/profile/
   "user/profile/email" = "[email protected]"
   "user/profile/name" = "John Doe"
---------------------------

解説
この方法は、allKeys() が返すフラットなリストではなく、階層構造を維持しながら設定を探索するのに適しています。デバッグや設定のエクスポート機能の実装に役立ちます。

カスタムのストレージ形式を実装する

QSettings は、カスタムのストレージ形式を登録する機能を提供しています(QSettings::registerFormat())。これにより、独自の設定ファイル形式(XML、JSONなど)を読み書きする関数を実装し、それを QSettings のバックエンドとして使用できます。このカスタム実装内で、すべてのキーを列挙する独自のロジックを記述できます。

ユースケース

  • QSettings のデフォルトの動作(レジストリ、INIなど)が適さない場合。
  • 既存のデータ構造(QMap<QString, QVariant>など)から直接設定を読み書きしたい場合。
  • アプリケーションが特定のカスタム設定ファイル形式を使用する必要がある場合。

概念的なコード例(簡略化):

#include <QCoreApplication>
#include <QSettings>
#include <QDebug>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>

// カスタムの読み込み関数(JSON形式を想定)
bool myJsonReadFunc(QIODevice &device, QSettings::SettingsMap &map) {
    QJsonDocument doc = QJsonDocument::fromJson(device.readAll());
    if (doc.isObject()) {
        QJsonObject obj = doc.object();
        // JSONオブジェクトをフラットなキー/値のマップに変換
        // ここで再帰的にJSONを走査し、mapにキーと値を挿入
        // 例: "key1": "value1", "group/key2": "value2"
        for (auto it = obj.constBegin(); it != obj.constEnd(); ++it) {
            if (it.value().isObject()) {
                // サブオブジェクトを処理するためのカスタムロジック(再帰など)
                // これは複雑になる可能性があるため、簡易的にスキップ
                qDebug() << "Warning: Nested JSON objects are not fully supported in this simple example.";
            } else {
                map.insert(it.key(), it.value().toVariant());
            }
        }
        return true;
    }
    return false;
}

// カスタムの書き込み関数(JSON形式を想定)
bool myJsonWriteFunc(QIODevice &device, const QSettings::SettingsMap &map) {
    QJsonObject obj;
    for (auto it = map.constBegin(); it != map.constEnd(); ++it) {
        // フラットなキー/値のマップをJSONオブジェクトに変換
        // QSettingsのキーはパス区切り文字 '/' を含むので、JSONの階層に変換する必要がある
        // 例: "group/key" を { "group": { "key": value } } に変換
        // これは非常に複雑になるため、簡易的にフラットなJSONで出力
        obj[it.key()] = QJsonValue::fromVariant(it.value());
    }
    device.write(QJsonDocument(obj).toJson(QJsonDocument::Indented));
    return true;
}

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    // カスタムフォーマットを登録
    // "json" 拡張子を使用
    QSettings::Format jsonFormat = QSettings::registerFormat("json", myJsonReadFunc, myJsonWriteFunc);

    // カスタムフォーマットでQSettingsオブジェクトを作成
    QSettings settings("my_custom_settings.json", jsonFormat);

    // 設定値を保存
    settings.setValue("app/language", "fr_FR");
    settings.setValue("user/id", 123);
    settings.sync();

    qDebug() << "--- カスタムフォーマットからの設定キー ---";
    QStringList allKeys = settings.allKeys(); // ここでカスタム実装のallKeys()が呼び出される
    for (const QString &key : allKeys) {
        qDebug() << "  " << key << " = " << settings.value(key);
    }
    qDebug() << "--------------------------------------";

    // 注意: この例のmyJsonReadFunc/myJsonWriteFuncは非常に簡略化されており、
    // ネストされたキーの処理やJSONの正しい階層化は行っていません。
    // 実際のカスタムフォーマットでは、QMap<QString, QVariant> を適切にJSONにマッピングするロジックが必要です。

    return app.exec();
}

解説
この方法は非常に強力ですが、複雑さが増します。QSettings::SettingsMap はフラットなキー/値のペアで構成されるため、カスタムフォーマットの読み書き関数は、そのファイル形式の階層構造と QSettings::SettingsMap のフラットな構造との間の変換ロジックを実装する必要があります。特に、allKeys() が内部的に利用する SettingsMap を構築する読み込み関数が正しく実装されている必要があります。

QSettings は便利な抽象化を提供しますが、場合によってはINIファイルやXMLファイルなどを直接読み書きすることも可能です。この場合、QSettings::allKeys() に相当する機能は、自分でファイルの内容を解析してキーを抽出するロジックを実装することになります。

ユースケース

  • QSettings がサポートしない特定のファイル形式やセマンティクスを扱う必要がある場合。
  • 非常に単純な設定ファイルで、既存のパーサーを使用したい場合(例: QXmlStreamReader, QJsonDocument など)。
  • QSettings のオーバーヘッドを避けたい、またはより細かい制御が必要な場合。

コード例(INIファイルをQFileとQTextStreamで直接読み込む場合):

#include <QCoreApplication>
#include <QFile>
#include <QTextStream>
#include <QStringList>
#include <QDebug>

// INIファイルを直接読み込み、キーを抽出する関数
QStringList getAllKeysFromIniFile(const QString &filePath) {
    QStringList keys;
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qDebug() << "Error: Could not open file" << filePath;
        return keys;
    }

    QTextStream in(&file);
    QString currentGroup; // 現在のセクション/グループ
    while (!in.atEnd()) {
        QString line = in.readLine().trimmed();
        if (line.isEmpty() || line.startsWith(';') || line.startsWith('#')) {
            // 空行またはコメント行はスキップ
            continue;
        }

        if (line.startsWith('[') && line.endsWith(']')) {
            // セクションヘッダー
            currentGroup = line.mid(1, line.length() - 2);
        } else if (line.contains('=')) {
            // キー=値のペア
            int equalsIndex = line.indexOf('=');
            QString key = line.left(equalsIndex).trimmed();
            if (!currentGroup.isEmpty()) {
                keys.append(currentGroup + "/" + key); // グループ名を含むキー
            } else {
                keys.append(key); // ルートレベルのキー
            }
        }
    }
    file.close();
    return keys;
}

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    // サンプルINIファイルを作成(QSettingsを使って作成することもできますが、ここでは手動で)
    QString iniFilePath = QCoreApplication::applicationDirPath() + "/my_manual_settings.ini";
    QFile iniFile(iniFilePath);
    if (iniFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
        QTextStream out(&iniFile);
        out << "top_key_1=value1\n";
        out << "[SectionA]\n";
        out << "key_a=value_a\n";
        out << "key_b=value_b\n";
        out << "[SectionB]\n";
        out << "sub/key_c=value_c\n"; // QSettingsは '/' をサブキーの区切りとして解釈
        iniFile.close();
    } else {
        qDebug() << "Error: Could not create INI file.";
        return 1;
    }

    qDebug() << "--- 手動で解析したINIファイルのキー ---";
    QStringList parsedKeys = getAllKeysFromIniFile(iniFilePath);
    for (const QString &key : parsedKeys) {
        qDebug() << "  " << key;
    }
    qDebug() << "------------------------------------";

    return app.exec();
}

出力例

--- 手動で解析したINIファイルのキー ---
   "top_key_1"
   "SectionA/key_a"
   "SectionA/key_b"
   "SectionB/sub/key_c"
------------------------------------

解説
このアプローチは最も柔軟性が高いですが、設定の読み書きロジックをすべて自分で実装する必要があるため、複雑さが増します。また、エラー処理、データ型の変換、プラットフォーム間の互換性などを自分で考慮する必要があります。通常、QSettings の機能が十分である場合は、この方法を選択するメリットは小さいです。