Linux 嵌入式システムにおけるファイルベースの設定キャッシュ実装

Linux 嵌入式プラットフォーム上でアプリケーションを開発する際、データベースを移植せずにファイルストレージを使用して永続的なデータを保存することは有効な手段です。

以下の手順で、設定データをファイルに保存および読み出すためのコードを実装します。

1. データ構造の定義


// 設定情報構造体
typedef struct {
    char *key;
    char *value;
} SettingEntry;

2. 関数の宣言


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

// 定義済みマクロ
#define SETTING_FILE "settings.txt"
#define LANG_KEY "language"
#define TEMP_KEY "temperature"

// デフォルト設定値
static SettingEntry settings[] = {
    {LANG_KEY, "1"}, // 既定言語:英語
    {TEMP_KEY, "58"},
};
static int settingCount; // 設定項目数

// ファイルが空かどうかをチェック
int isEmptyFile(const char *filename);
// 設定ファイル初期化
void initializeSettings(const char *filename);
// 設定ファイル読み込み
void loadSettings(const char *filename);
// 指定キーの設定値取得
SettingEntry getSetting(const char *key);
// 指定キーの設定値更新
void updateSetting(const char *key, const char *value);
// 設定ファイル保存
int saveSettings();

3. 関数の定義


#include "configcache.h"

int isEmptyFile(const char *filename) {
    struct stat fileStat;
    if (stat(filename, &fileStat) < 0) {
        return -1;
    }
    return fileStat.st_size == 0;
}

// 設定ファイル初期化
void initializeSettings(const char *filename) {
    int emptyCheck = isEmptyFile(filename);
    DEBUG_PRINT("initializeSettings: %d\n", emptyCheck);
    if (emptyCheck == 1 || emptyCheck == -1) {
        FILE *file = fopen(filename, "w+");
        if (file != NULL) {
            int numEntries = sizeof(settings) / sizeof(settings[0]);
            for (int i = 0; i < numEntries; i++) {
                fprintf(file, "%s=%s\n", settings[i].key, settings[i].value);
                DEBUG_PRINT("fprintf: %d\n", i);
            }
            fflush(file);
            fclose(file);
        } else {
            perror("ファイルオープンエラー");
        }
    }
}

// 設定ファイル読み込み
void loadSettings(const char *filename) {
    FILE *file = fopen(filename, "r");
    if (file == NULL) {
        perror("ファイルオープンエラー");
        return;
    }
    char line[100];
    int count = 0;
    while (fgets(line, sizeof(line), file) != NULL) {
        char *delimiter = strchr(line, '=');
        if (delimiter == NULL) continue;
        *delimiter = '\0';
        settings[count].key = strdup(line);
        settings[count].value = strdup(delimiter + 1);
        DEBUG_PRINT("key: %s\n", settings[count].key);
        DEBUG_PRINT("value: %s\n", settings[count].value);
        count++;
    }
    fclose(file);
    settingCount = sizeof(settings) / sizeof(settings[0]);
    DEBUG_PRINT("読み込んだ設定数: %d\n", count);
    DEBUG_PRINT("設定配列サイズ: %d\n", settingCount);
}

// 指定キーの設定値取得
SettingEntry getSetting(const char *key) {
    SettingEntry entry;
    for (int i = 0; i < settingCount; i++) {
        if (strcmp(settings[i].key, key) == 0) {
            entry.key = strdup(settings[i].key);
            entry.value = strdup(settings[i].value);
            break;
        }
    }
    return entry;
}

// 指定キーの設定値更新
void updateSetting(const char *key, const char *value) {
    int saveRequired = 0;
    for (int i = 0; i < settingCount; i++) {
        if (strcmp(settings[i].key, key) == 0) {
            free(settings[i].value);
            settings[i].value = strdup(value);
            DEBUG_PRINT("updateSetting: %s=%s\n", key, value);
            saveRequired = 1;
        }
    }
    if (saveRequired) {
        saveSettings();
    }
}

// 設定ファイル保存
int saveSettings() {
    FILE *file = fopen(SETTING_FILE, "w");
    if (file == NULL) {
        perror("ファイルオープンエラー");
        return -1;
    }
    for (int i = 0; i < settingCount; i++) {
        fprintf(file, "%s=%s\n", settings[i].key, settings[i].value);
        DEBUG_PRINT("saveSettings: %s=%s\n", settings[i].key, settings[i].value);
    }
    fflush(file);
    fclose(file);
    return 0;
}

4. 初期化と関数呼び出しの例


// 設定キャッシュ初期化
initializeSettings(SETTING_FILE);
loadSettings(SETTING_FILE);
// 現在の言語設定取得
DEBUG_PRINT("現在の言語: %s\n", getSetting(LANG_KEY).value);

5. マクロによるデバッグ出力の切り替え(configcache.h に記述)


#define DEBUG_SWITCH 1 // デバッグ出力有効
#if DEBUG_SWITCH
#define DEBUG_PRINT(format, ...) printf(format, ##__VA_ARGS__)
#else
#define DEBUG_PRINT(format, ...)
#endif

タグ: linux 埋め込みシステム ファイル操作 C言語 設定管理

6月2日 16:39 投稿