一般來說,程式多少都會有一些自己的配置資訊要儲存,不論是通常用的儲存到INI還是註冊表,或者是XML甚至YAML,總歸是要寫不少代碼處理的。
問題的麻煩在於,程式中實現操作配置資訊通常並不需要關注它是儲存在什麼地方,以什麼格式儲存,但是傳統的方法不論是調用TIniFile還是TRegistry或者是DOM,都是需要開發人員花一些時間精力浪費在這上面。
我前一陣寫個小程式,不高興弄配置這些麻煩事,於是利用前些年寫的一個架構代碼,實現了一套通用的配置序列化機制,這樣配置資訊管理起來就方便多了。
代碼詳見MDConfig單元。
基本組成是這樣:
TMCustomConfigSection
類實現了IMSerializable介面(定義在架構的MDComm中),意味著它可以被遞迴序列化——不過在已實現的INI檔案和註冊表檔案序列化
中,這種遞迴僅限於一層:即一個設定檔可以包括多個配置段,但是配置段下不能再有配置段。當然,架構中實現的通用序列化(二進位和XML)不受此限。
TMCustomConfig類則是可序列化的設定檔,派生自TPersistent。這個類裡除了可以包含配置資訊以外,還可以包括配置段。
TMCustomConfigSerializer類則是配置序列化基類,實現配置序列化的公用部分——即與具體序列化方式無關的部分。
TMIniSerializer類是INI檔案的序列化類別,通過它可以把設定檔序列化到INI檔案中去。
TMRegSerializer類是註冊表序列化類別。
配置的基本使用方法是這樣的:
分別從TMCustomConfigSection和TMCustomConfig派生自己的配置段類和配置類,在其中定義設定項目供程式使用。範例程式碼如:
TMTestConfigSection = class(TMCustomConfigSection)
Private
FStringItem : String;
FIntItem : Integer;
FFloatItem : Double;
FDateItem : TDateTime;
Published
Property StringItem : String Read FStringItem Write FStringItem;
Property IntItem : Integer Read FIntItem Write FIntItem;
Property FloatItem : Double Read FFloatItem Write FFloatItem;
Property DateItem : TDateTime Read FDateItem Write FDateItem;
End;
TMTestConfig = class(TMCustomConfig)
Private
FSectionItem : TMTestConfigSection;
FStringItem : String;
public
Constructor Create(aDefaultSerializer : IMSerializer = Nil);
destructor Destroy; Override;
Published
Property SectionItem : TMTestConfigSection Read FSectionItem Write FSectionItem;
Property StringItem : String Read FStringItem Write FStringItem;
End;
Constructor TMTestConfig.Create(aDefaultSerializer : IMSerializer = Nil);
begin
Inherited Create(aDefaultSerializer);
FSectionItem := TMTestConfigSection.Create();
end;
destructor TMTestConfig.Destroy;
begin
FSectionItem.Free;
Inherited
end;
序
列化方式則可以自由選擇目前已經實現的四種:INI檔案,註冊表,二進位檔案,XML。序列化操作也可以選擇預設序列化或是指定序列化。預設序列化就是在
Config物件建構時傳入預設的序列化方式,指定序列化就是在調用Config對象的Load/Save方法時指定序列方式。當然,即使設定了預設序列
化方式,也是可以在調用Load/Save方法時重新指定的。
預設序列化:
conf := TMTestConfig.Create(TMIniSerializer.Create('e:/temp/test.ini'));
conf.StringItem := 'This is default section item';
conf.SectionItem.StringItem := 'This is Section item';
conf.SectionItem.IntItem := 12345;
conf.SectionItem.FloatItem := 9.87654;
conf.SectionItem.DateItem := EncodeDate( 2009, 01, 02 );
conf.Save;
指定序列化:
conf := TMTestConfig.Create;
conf.Load(TMIniSerializer.Create('e:/temp/test.ini'));
conf.Save(TMRegSerializer.Create(HKEY_CURRENT_USER, 'software/mental studio/devotee/test'));
注意,其中序列化器是通過引用計數維護的,會自動釋放,不需要顯示釋放。
mdf架構全部源碼下載。
只使用配置序列化部分的話,只需要MDComm和MDConfig兩個單元檔案(二進位和XML序列化需要MSerializ單元)。
在BCB中使用的特別注意事項:
要用一個Delphi單元來定義配置類,因為用到了Delphi的RTTI,雖然用C++來寫配置類也可以編譯,但是會發生執行階段錯誤。特別關鍵的是序列化器對象必須在Delphi單元中建立。形如:
Constructor TMainConfig.Create(aIniName : String);
begin
Inherited Create(TMIniSerializer.Create(aIniName, 'Default'));
end;
// 然後在BCB中這樣使用
TMainConfig * MainCfg = new TMainConfig(ChangeFileExt(Application->ExeName,".ini"));