前言
每個應用程式都需要持久化配置資訊。Windows 平台上主流有三種方案:註冊表、INI 檔案、自定義二進制檔案。本文基於 C++Builder (VCL) 實作經驗,詳細比較三者 API 用法、優缺點、適用場景與安全性考量。
一、方案一:Windows 註冊表
核心類別 TRegistry (需 #include <Registry.hpp>)
| 屬性/方法 | 用途 |
RootKey | 設定/取得根鍵 (預設 HKEY_CURRENT_USER) |
OpenKey(Key, CanCreate) | 開啟鍵,CanCreate=true 不存在則建立 |
CloseKey() | 關閉鍵並寫入磁碟 |
KeyExists/ValueExists | 檢查鍵/值是否存在 |
ReadString/WriteString | 讀寫字串 (另有 Integer/Bool/Binary 等) |
讀取配置範例
void __fastcall ReadConfig() {
TRegistry* reg = new TRegistry();
reg->RootKey = HKEY_LOCAL_MACHINE;
if (reg->OpenKey("\\Software\\MyInfo", true)) {
if (reg->ValueExists("DataPath"))
SysConfig.DataPath = reg->ReadString("DataPath");
else
SysConfig.DataPath = DefaultPath;
}
reg->CloseKey();
delete reg;
}
寫入配置範例
void __fastcall SaveConfig() {
TRegistry* reg = new TRegistry();
reg->RootKey = HKEY_LOCAL_MACHINE;
if (reg->OpenKey("\\Software\\MyInfo", true))
reg->WriteString("DataPath", SysConfig.DataPath);
reg->CloseKey();
delete reg;
}
優缺點分析
| 優點 | 缺點 |
| 用戶難以手動修改/竄改 | Windows 版本間結構差異 |
| 二進制儲存相對隱蔽 | NT/2000+ 權限限制 (需管理員) |
| 系統級標準化管理 | 用戶反感軟體「髒污」註冊表 |
| 支援複雜資料型別 | 跨平台移植困難 |
催生「綠色軟體」概念:不寫註冊表、不依賴系統目錄、單檔可攜。
二、方案二:INI 設定檔
核心類別 TIniFile (需 #include <inifiles.hpp>)
[LastConfig]
DefaultDir=E:\xxx
常用方法
| 方法 | 說明 |
TIniFile(FileName) | 建立/開啟 INI,無路徑則放系統目錄 |
SectionExists | 檢查區段是否存在 |
ReadString(Section, Ident, Default) | 讀取字串,不存在返回 Default |
WriteString(Section, Ident, Value) | 寫入字串 |
讀取範例
void __fastcall ReadConfig() {
AnsiString ExePath = ExtractFileName(ParamStr(0));
TIniFile* regKey = new TIniFile(ExePath + "TrimTxt.ini");
DefaultDir = regKey->ReadString("LastConfig", "DefaultDir", ExePath);
delete regKey;
}
寫入範例
void __fastcall SaveConfig() {
AnsiString ExePath = ExtractFileName(ParamStr(0));
TIniFile* regKey = new TIniFile(ExePath + "TrimTxt.ini");
regKey->WriteString("LastConfig", "DefaultDir", DefaultDir);
delete regKey;
}
優缺點分析
| 優點 | 缺點 |
| 用戶可手工編輯修改 | 不適合複雜結構資料 |
| 跨平台可移植 (文字格式) | 檔案易損壞/誤刪 |
| 結構清晰 (Section/Key/Value) | 大量讀寫效能較差 |
| 綠色軟體首選 | 無型別安全 (全字串) |
三、方案三:自定義二進制檔案
結構體定義
struct UserInfo {
char UserName[10];
char PassWord[16];
int Level[24];
};
UserInfo UserInfo;
方式 A:傳統 C 風格 fopen/fread/fwrite
bool __fastcall ReadConfig() {
FILE* ptr = fopen(FileName.c_str(), "rb");
if (!ptr) return false;
fseek(ptr, 0, SEEK_END);
if (ftell(ptr) != sizeof(UserInfo)) { fclose(ptr); return false; } // 檢查損壞
fseek(ptr, 0, SEEK_SET);
fread(&UserInfo, sizeof(UserInfo), 1, ptr);
fclose(ptr);
return true;
}
void __fastcall SaveConfig() {
FILE* ptr = fopen(FileName.c_str(), "wb");
if (!ptr) return;
fwrite(&UserInfo, sizeof(UserInfo), 1, ptr);
fclose(ptr);
}
方式 B:VCL 流 TMemoryStream (習慣用法)
bool __fastcall ReadConfig() {
TMemoryStream* ms = new TMemoryStream();
ms->LoadFromFile(FileName);
if (ms->Size != sizeof(UserInfo)) { delete ms; return false; }
ms->Seek(0, soFromBeginning);
ms->ReadBuffer(&UserInfo, sizeof(UserInfo));
delete ms;
return true;
}
void __fastcall SaveConfig() {
TMemoryStream* ms = new TMemoryStream();
ms->WriteBuffer(&UserInfo, sizeof(UserInfo));
ms->Seek(0, soFromBeginning);
ms->SaveToFile(FileName);
delete ms;
}
優缺點分析
| 優點 | 缺點 |
| 支援任意複雜資料結構 | 程式碼較繁瑣 |
| 讀寫速度快 (二進制直接記憶體映射) | 檔案易被刪除/竄改 |
| 可加密/校驗和防竄改 | 跨平台/跨編譯器相容性差 (對齊、位序) |
| 單檔案自包含 | 版本演進需自行處理 |
四、綜合比較與選型建議
| 場景 | 推薦方案 | 理由 |
| 系統級設定、安全性要求高 | 註冊表 | 權限隔離、標準化管理 |
| 用戶偏好設定、綠色軟體、跨平台 | INI / JSON / XML | 可讀、可手工編輯、可攜帶 |
| 大量結構化資料、高效能、內部儲存 | 二進制檔案 / SQLite | 速度快、空間效率高 |
| 現代 C++ 專案 | JSON (nlohmann) + 檔案 | 型別安全、標準化、生態豐富 |
五、作者心得
「若非安全性要求,檔案儲存最靈活、最快速、最常用。註冊表與 INI 各有千秋,一切看專案需求與團隊習慣。」