Write/Read Record to/from IniFile with WriteBinaryStream/ReadBinaryStream?

In Delphi (XE7) I need to store a record in an IniFile with WriteBinaryStream:

Pseudocode:

IniFile.WriteBinaryStream('ASection', 'AName', GetStream(MyRecord));

Open in new window


Then read the single record fields with a simple method like:

Pseudocode:

MyRecord := GetRecordFromStream(Inifile.ReadBinaryStream(...));
Value1 := MyRecord.ValueX;
Value2 := MyRecord.Valuey;

Open in new window


How can all this be done?
PeterDelphinAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jimyXCommented:
Writing a Record to Stream is not direct, check this link.

On the other hand you can use a StringList Values feature:
procedure TForm1.Button1Click(Sender: TObject);
var
  ii:Tinifile;
  memstr:TStream;
  strlst:TStrings;
begin
  memstr:=TMemoryStream.Create;
  strlst:=TStringList.Create;
  ii:=Tinifile.Create('test.ini');
  try
    ii.ReadBinaryStream('ASection', 'AName', memstr);
    strlst.LoadFromStream(memstr);

    showmessage(strlst.ValueFromIndex[0]); // show first value
    showmessage(strlst.Text); // View all the values
  finally
    ii.Free;
    memstr.Free;
    strlst.Free;
  end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
  ii:Tinifile;
  memstr:TStream;
  strlst:TStrings;
begin
  memstr:=TMemoryStream.Create;
  strlst:=TStringList.Create;
  ii:=Tinifile.Create('test.ini');
  try
    strlst.Values['value1']:= 'Valuex';
    strlst.Values['value2']:= 'Valuey';
    strlst.SaveToStream(memstr);
    memstr.Position:= 0;

    ii.WriteBinaryStream('ASection', 'AName', memstr);
  finally
    ii.Free;
    memstr.Free;
    strlst.Free;
  end;
end;

Open in new window

0
PeterDelphinAuthor Commented:
With your methods I can store and read only strings. To store and read a stringlist to/from an inifile I wouldn't need WriteBinaryStream/ReadBinaryStream. That's why I have to use a record: Using different data types.
0
jimyXCommented:
I understand. That was just an example of passing TStringList to Stream to ini.
But you could easily rework that with the code form SO link provided to add records.
0
Introduction to Web Design

Develop a strong foundation and understanding of web design by learning HTML, CSS, and additional tools to help you develop your own website.

PeterDelphinAuthor Commented:
On the linked page I found another link: https://code.google.com/p/kblib/

TKBDynamic allows to save/load/get(binary)size/compare any dynamic type with only one line of code. This is a very good library and perfect for saving a record to a stream. So I have created this code to achieve what was my question:

// Save record to IniFile:

memstr := TMemoryStream.Create;
try
    TKBDynamic.WriteTo(memstr, AMyRecord, TypeInfo(TMyRecord));
    memstr.Position := 0;
    IniFile.WriteBinaryStream(ASection, AName, memstr);
finally
    memstr.Free;
end;

// Read record From IniFile:

// Check whether Key exists to avoid StreamRead-Error:
if not IniFile.ValueExists(ASection, AName) then
    EXIT;
memstr := TMemoryStream.Create;
try
  IniFile.ReadBinaryStream(ASection, AName, memstr);
  memstr.Position := 0;
  TKBDynamic.ReadFrom(memstr, AMyRecord, TypeInfo(TMyRecord));
  Result := AMyRecord;
finally
  memstr.Free;
end;

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
PeterDelphinAuthor Commented:
This is the best solution for the initial question: It is easy to implement and allows to save records to an inifile.
0
PeterDelphinAuthor Commented:
Accept. This system is very confusing. I don't know whether I should Object or Object. What does this mean?
0
Sinisa VukSoftware architectCommented:
Even you close, ... I can suggest writing Base64 encoded binary record. It is quite easy to do this.
0
PeterDelphinAuthor Commented:
@Sinisa Vuk AFAIS, doesn't uKBDynamic just do this?
0
Sinisa VukSoftware architectCommented:
example at bottom (StreamToHexStr64)
http://www.delphipages.com/forum/showthread.php?t=154336
0
PeterDelphinAuthor Commented:
@Sinisa Vuk How does this relate to my question " store a record in an IniFile with WriteBinaryStream"? The question is not how to convert a stream to a string representation but how to convert a record to a stream.
0
Sinisa VukSoftware architectCommented:
this is my example:

uses ..., DCPbase64;

Type
  PMyRec = ^TMyRec;
  TMyRec = record
    ValueX: integer;
    ValueY: Integer;
  end;

procedure TForm1.Button5Click(Sender: TObject);
var
  ini: TIniFile;
  myrec: TMyRec;
  sRec: AnsiString;
begin
  myrec.ValueX := 200;
  myrec.ValueY := 100;

  ini := TIniFile.Create(ChangeFileExt(Application.ExeName, '.ini'));
  try
    //make string long enough
    SetLength(sRec,((SizeOf(myrec)+2) div 3) * 4);
    //encode
    Base64Encode(@myrec, PAnsiChar(sRec), SizeOf(myrec));
    //write to ini
    ini.WriteString('Data', 'MyRec', sRec);
  finally
    ini.Free;
  end;
end;

procedure TForm1.Button6Click(Sender: TObject);
var
  ini: TIniFile;
  myrec: TMyRec;
  sRec: AnsiString;
begin
  ini := TIniFile.Create(ChangeFileExt(Application.ExeName, '.ini'));
  try
    //read from ini
    sRec := ini.ReadString('Data', 'MyRec', '');
    if Length(sRec) > 0 then
    begin
      //decode
      sRec := Base64DecodeStr(sRec);
      //set record
      if Length(sRec) = SizeOf(myrec) then
        CopyMemory(@myrec, PAnsiChar(sRec), SizeOf(myrec));
    end;
  finally
    ini.Free;
  end;
end;

Open in new window


...and for this example I use unit for base 64 encoding: DCPbase64.pas
Alternatively, you can use some other.
0
PeterDelphinAuthor Commented:
This is the best solution for the initial question: It is easy to implement and allows to save records to an inifile.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.