Precisa fazer persistência local de configurações ?
Então um dia você ainda vai usar um arquivo JSON ao invés de um INI.

Ver uma classe para TJsonFile     Exemplo

  • Usando RTTI para escrever no TJsonFile

Ver o exemplo com fazer persistência de objeto usando RTTI para descobrir as propriedades a guardar no TJsonFile.WriteObject(…). Do outro lado TJsonFile.ReadObject(…) lê as propriedades no JSONFile e popula o objeto.

O funcionamento do RTTI é o mesmo descrito no post anterior

 

É comum encontrar sistemas que utilizam arquivos TIniFiles para persistir informações locais.
O uso de TIniFiles impõe escrever muitas linhas para gravação e leitura do conteúdo.
No exemplo mostro como utilizar RTTI para gravar as propriedades de um objeto diretamente no arquivo INI / carregando as informações do arquivo INI para o objeto.

  • Para o exemplo considerar a seguinte classe base para gravação no arquivo INI:

[code]
// Classe a ser gravar no INI
TIniSecaoClass = class
private
Fbase_datetime: TDatetime;
Fbase_numerico: Double;
Fbase_string: string;
Fbase_integer: integer;
Fbase_boolean: Boolean;
procedure Setbase_datetime(const Value: TDatetime);
procedure Setbase_numerico(const Value: Double);
procedure Setbase_string(const Value: string);
procedure Setbase_integer(const Value: integer);
procedure Setbase_boolean(const Value: Boolean);
public
// propriedades a serem gravadas ou lidas no INI
property base_string: string read Fbase_string write Setbase_string;
property base_datetime: TDatetime read Fbase_datetime
write Setbase_datetime;
property base_numerico: Double read Fbase_numerico write Setbase_numerico;
property base_integer: integer read Fbase_integer write Setbase_integer;
property base_boolean: Boolean read Fbase_boolean write Setbase_boolean;
end;
[/code]

  • HELPERs para adicionar funcionalidade aos objetos existentes no DELPHI.

[code lang=”pascal”]

uses IniFiles, System.DateUtils, System.Rtti, System.TypInfo;

type

{
Fragmento de: System.Classes.Helper
https://github.com/amarildolacerda/helpers/blob/master/System.Classes.Helper.pas
}
TMemberVisibilitySet = set of TMemberVisibility;

// RTTI para pegar propriedades do object
TObjectHelper = class helper for TObject
private
procedure GetPropertiesItems(AList: TStrings;
const AVisibility: TMemberVisibilitySet);
end;

// Adiciona Uso de RTTI para o INI
TCustomIniFileHelper = class Helper for TCustomIniFile
private
procedure WriteObject(const ASection: string; AObj: TObject);
procedure ReadObject(const ASection: string; AObj: TObject);
public
end;

// Adiciona funções ao TValue
TValueHelper = record helper for TValue
private
function IsNumeric: Boolean;
function IsFloat: Boolean;
function AsFloat: Extended;
function IsBoolean: Boolean;
function IsDate: Boolean;
function IsDateTime: Boolean;
function IsDouble: Boolean;
function AsDouble: Double;
function IsInteger: Boolean;
end;

[/code]

  • Métodos para gravação e leitura para o arquivo INI utilizando RTTI:

[code]
procedure TCustomIniFileHelper.WriteObject(const ASection: string;
AObj: TObject);
var
aCtx: TRttiContext;
AFld: TRttiProperty;
AValue: TValue;
begin
aCtx := TRttiContext.Create;
try
for AFld in aCtx.GetType(AObj.ClassType).GetProperties do
begin
if AFld.Visibility in [mvPublic] then
begin
AValue := AFld.GetValue(AObj);
if AValue.IsDate or AValue.IsDateTime then
WriteString(ASection, AFld.Name, ISODateTimeToString(AValue.AsDouble))
else if AValue.IsBoolean then
WriteBool(ASection, AFld.Name, AValue.AsBoolean)
else if AValue.IsInteger then
WriteInteger(ASection, AFld.Name, AValue.AsInteger)
else if AValue.IsFloat or AValue.IsNumeric then
WriteFloat(ASection, AFld.Name, AValue.AsFloat)
else
WriteString(ASection, AFld.Name, AValue.ToString);
end;
end;
finally
aCtx.free;
end;
end;

procedure TCustomIniFileHelper.ReadObject(const ASection: string;
AObj: TObject);
var
aCtx: TRttiContext;
AFld: TRttiProperty;
AValue, ABase: TValue;
begin
aCtx := TRttiContext.Create;
try
for AFld in aCtx.GetType(AObj.ClassType).GetProperties do
begin
if AFld.Visibility in [mvPublic] then
begin
ABase := AFld.GetValue(AObj);
AValue := AFld.GetValue(AObj);
if ABase.IsDate or ABase.IsDateTime then
AValue := ISOStrToDateTime(ReadString(ASection, AFld.Name,
ISODateTimeToString(ABase.AsDouble)))
else if ABase.IsBoolean then
AValue := ReadBool(ASection, AFld.Name, ABase.AsBoolean)
else if ABase.IsInteger then
AValue := ReadInteger(ASection, AFld.Name, ABase.AsInteger)
else if ABase.IsFloat or ABase.IsNumeric then
AValue := ReadFloat(ASection, AFld.Name, ABase.AsFloat)
else
AValue := ReadString(ASection, AFld.Name, ABase.asString);
AFld.SetValue(AObj, AValue);
end;
end;
finally
aCtx.free;
end;
end;
[/code]

  • Gravando o objeto no arquivo INI:

[code]

procedure TForm6.Button2Click(Sender: TObject);
begin
// grava o objeto OBJ no INI
// inicializar OBJ antes de executar….
with TIniFile.Create(‘teste.ini’) do
try
WriteObject(‘SecaoClass’, obj);
finally
free;
end;

end;
[/code]

  • Carregando o objeto com os dados do INI:

[code]
procedure TForm6.Button4Click(Sender: TObject);
begin
// Ler os dados do INI para o OBJ
with TIniFile.Create(‘teste.ini’) do
try
ReadObject(‘SecaoClass’, obj);
finally
free;
end;
end;
[/code]

Código Fonte no GIT

 

Para escrever arquivos JSON com as configurações ver o post seguinte