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