AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Record mit dyn.Array speichern

Ein Thema von Sinderion · begonnen am 5. Jan 2012 · letzter Beitrag vom 12. Jan 2012
Antwort Antwort
Sinderion

Registriert seit: 23. Nov 2007
Ort: Oberösterreich
19 Beiträge
 
Delphi XE7 Architect
 
#1

Record mit dyn.Array speichern

  Alt 5. Jan 2012, 19:14
Delphi-Version: 2009
Hallo zusammen!

Wie speichert man am besten ein Record, welches ein dyn. Array enthält? "Normale" Records kann man ja relativ bequem mit file of Record speichern, jedoch nur, wenn das Record eine feste Größe hat. Wie ich ein (einzelnes) Array in einem Stream speichern kann weiß ich in etwa (Anzahl der Elemente speichern, dann die Elemente ... usw). So könnte ich zwar das ganze Record speichern, ist bei den vielen Eigenschaften jedoch etwas umständlich. Deshalb frage ich mich, ob es nicht eine kürzere Möglichkeit gibt, diese beiden Speichermethoden irgendwie zu verbinden (also das ganze Record samt Array in eine Datei/Stream).

Das Record besteht aus (z.Z.) 30 Eigenschaften und eben 1 dyn. Array.
Daniel
  Mit Zitat antworten Zitat
Benutzerbild von olee
olee

Registriert seit: 16. Feb 2008
Ort: Boppard
540 Beiträge
 
Turbo Delphi für Win32
 
#2

AW: Record mit dyn.Array speichern

  Alt 5. Jan 2012, 19:31
Der einzige Ansatz der mir auf die Schnelle einfällt wäre es, das Array als letztes im Record zu deklarieren und dann mit einem Schreibbefehl alle vorherigen Einträge auf einmal zu schreiben, indem man von Anfang des Arrays bis ein Byte vor der Adresse des Arrays schreibt.
Björn Zeutzheim
Codename: Performancepumpe
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.338 Beiträge
 
Delphi 12 Athens
 
#3

AW: Record mit dyn.Array speichern

  Alt 5. Jan 2012, 19:36
Theoretisch, indem du den dynamischen Teil manuell speicherst.

Am Besten speicherst du diesen Record aber garnicht direkt, also jedenfalls nicht den Teil, wo das dyn. Array liegt.
Denn wenn du diesen Record wieder laden würdest, würdest DU die automatische Speicherverwaltung des Arrays zerschießen.
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Sinderion

Registriert seit: 23. Nov 2007
Ort: Oberösterreich
19 Beiträge
 
Delphi XE7 Architect
 
#4

AW: Record mit dyn.Array speichern

  Alt 5. Jan 2012, 20:28
Wie meinst du das, den dynamischen Teil manuell speichern? So ähnlich wie ich es beschrieben habe? Es wäre auch möglich, alle Records(ohne den dynamischen Teil) in einer Datei zu speichern und alle arrays in einer anderen Datei. Nur das Problem ist nach wie vor: wie verlinke ich diese Informationen dann, also dass in dem Record dann (eventuell in einer neuen Eigenschaft) irgendwie hinterlegt ist, wo sich das zugehörige Array befindet.

Zitat:
dann mit einem Schreibbefehl alle vorherigen Einträge auf einmal zu schreiben
Da blicke ich nicht ganz durch. Wie kann ich alle Eigenschaften des Records auf einmal speichern?
Daniel
  Mit Zitat antworten Zitat
Furtbichler
(Gast)

n/a Beiträge
 
#5

AW: Record mit dyn.Array speichern

  Alt 6. Jan 2012, 06:47
Delphi-Quellcode:
Type
  TMyRecord = Record
    A,B,C,D : TSomeType;
    E : TDynArray;
  Procedure SaveToStream (aStream : TStream);
   
  End;

Procedure TMyRecord.SaveToStream(aStream : TStream);
Var
  numberOFixedBytes,
  elementCount,
  firstElement : Integer;
Begin
// statischer/fester Teil
  numberOFixedBytes := PChar(Integer(@E)-Integer(@A));
  aStream.Write(A,NumberOfFixedBytes);

// Für jedes dynamische Array folgenden Code ausführen
  elementCount := Length(E);
  aStream.Write(elementCount);
  if elementCount>0 then begin
    firstElement := Low(E);
    aStream.Write(E[firstElement], elementCount*SizeOf(E[firstElement]));
  end
End;
Laden geht genauso (analog). Wenn Du das as Recordmethoden implementierst, sieht das doch hübsch aus.
  Mit Zitat antworten Zitat
Benutzerbild von olee
olee

Registriert seit: 16. Feb 2008
Ort: Boppard
540 Beiträge
 
Turbo Delphi für Win32
 
#6

AW: Record mit dyn.Array speichern

  Alt 6. Jan 2012, 10:55
Das ist genau das, was ich meinte.
Aber das ist auch keine wirklich saubere Art um ein record zu speichern.
Ich selber verwende eigentlich immer einen class-helper für TStream mit Methoden wie WriteInteger und ReadInteger, welche ich dann für jeden Stream nutzen kann.
Ich werde gleich mal ein Beispiel posten.
Leider geht das gerade nicht gut, da ich mobil online bin.

MFG
Björn Zeutzheim
Codename: Performancepumpe
  Mit Zitat antworten Zitat
Benutzerbild von olee
olee

Registriert seit: 16. Feb 2008
Ort: Boppard
540 Beiträge
 
Turbo Delphi für Win32
 
#7

AW: Record mit dyn.Array speichern

  Alt 6. Jan 2012, 12:02
So nun mal richtig.

Dies ist der Stream-helper den ich immer verwende:
Delphi-Quellcode:
  TStreamHelper = class helper for TStream
    function ReadBoolean: Boolean;
    procedure WriteBoolean(v: Boolean);
    Function ReadByte : Byte;
    Procedure WriteByte(v : Byte);
    Function ReadWord : Word;
    Procedure WriteWord(v : Word);
    function ReadInteger: Integer;
    procedure WriteInteger(v: Integer);
    function ReadCardinal: Cardinal;
    procedure WriteCardinal(v: Cardinal);
    function ReadInt64: Int64;
    procedure WriteInt64(v: Int64);
    function ReadSingle: Single;
    procedure WriteSingle(v: Single);
    function ReadDouble: Double;
    procedure WriteDouble(v: Double);
    function ReadString: AnsiString;
    procedure WriteString(const v: AnsiString);
    function ReadChars(count: Integer): AnsiString;
    procedure WriteChars(const v: AnsiString; count: Integer);
    function ReadWideString: WideString;
    procedure WriteWideString(const v: WideString);
    function ReadWideChars(count: Integer): WideString;
    procedure WriteWideChars(const v: WideString; count: Integer);
    function StreamMove(Src, Dst, Count: Int64): Int64;
  end;

implementation

{$ifdef VER140}{$REGION 'TStreamHelper'}{$endif}

function TStreamHelper.StreamMove(Src, Dst, Count: Int64): Int64;
var
  Buffer : Array [0..1024 * 32 - 1] of Byte;
  ByteCount : Integer;
  ReadBytes : Integer;
begin
  Result := 0;
  while Count > 0 do
  begin
    If Count > length(Buffer) then
      ByteCount := length(Buffer)
    else
      ByteCount := Count;

    Position := Src;
    ReadBytes := Read(Buffer, ByteCount);
    If ReadBytes <> ByteCount then
      raise Exception.Create('Abnormal exception. Could not read desired bytes from the file.');

    Position := Dst;
    ByteCount := Write(Buffer, ReadBytes);
    If ByteCount <> ReadBytes then
      raise Exception.Create('Abnormal exception. Could not write desired bytes to the file.');

    Count := Count - ByteCount;
    Result := Result + ByteCount;
    Src := Src + ByteCount;
    Dst := Dst + ByteCount;
  end;
End;

Function TStreamHelper.ReadBoolean : Boolean;
Begin
  Read(Result, 1);
End;

Procedure TStreamHelper.WriteBoolean(v : Boolean);
Begin
  Write(v, 1);
End;

Function TStreamHelper.ReadByte : Byte;
Begin
  Read(Result, 1);
End;

Procedure TStreamHelper.WriteByte(v : Byte);
Begin
  Write(v, 1);
End;

Function TStreamHelper.ReadWord : Word;
Begin
  Read(Result, 2);
End;

Procedure TStreamHelper.WriteWord(v : Word);
Begin
  Write(v, 2);
End;

Function TStreamHelper.ReadInteger : Integer;
Begin
  Read(Result, 4);
End;

Procedure TStreamHelper.WriteInteger(v : Integer);
Begin
  Write(v, 4);
End;

Function TStreamHelper.ReadCardinal : Cardinal;
Begin
  Read(Result, 4);
End;

Procedure TStreamHelper.WriteCardinal(v : Cardinal);
Begin
  Write(v, 4);
End;

function TStreamHelper.ReadInt64: Int64;
begin
  Read(Result, 8);
end;

procedure TStreamHelper.WriteInt64(v: Int64);
begin
  Write(v, 8);
end;

Function TStreamHelper.ReadSingle : Single;
Begin
  Read(Result, 4);
End;

Procedure TStreamHelper.WriteSingle(v : Single);
Begin
  Write(v, 4);
End;

function TStreamHelper.ReadDouble: Double;
begin
  Read(Result, 8);
end;

procedure TStreamHelper.WriteDouble(v: Double);
begin
  Write(v, 8);
end;

Procedure TStreamHelper.WriteString(Const v : AnsiString);
Var Len : Integer;
Begin
  Len := Length(v);
  Write(Len, SizeOf(Len));
  Write(PChar(v)^, Len);
End;

Function TStreamHelper.ReadString: AnsiString;
Var Len : Integer;
Begin
  Read(Len, SizeOf(Len));
  //If len > 20000 Then exit;
  SetLength(Result, Len);
  Read(PChar(Result)^, Len);
End;

Procedure TStreamHelper.WriteChars(Const v : AnsiString; count: Integer);
Begin
  Write(PAnsiChar(v)^, count);
End;

Function TStreamHelper.ReadChars(count: Integer) : AnsiString;
Begin
  SetLength(Result, count);
  Read(PAnsiChar(Result)^, count);
End;

Procedure TStreamHelper.WriteWideString(Const v : WideString);
Var Len : Integer;
Begin
  Len := Length(v);
  Write(Len, SizeOf(Len));
  Write(PWideChar(v)^, Len * 2);
End;

Function TStreamHelper.ReadWideString: WideString;
Var Len : Integer;
Begin
  Read(Len, SizeOf(Len));
  //If len > 20000 Then exit;
  SetLength(Result, Len);
  Read(PWideChar(Result)^, Len * 2);
End;

Procedure TStreamHelper.WriteWideChars(Const v : WideString; count: Integer);
Begin
  Write(PWideChar(v)^, count * 2);
End;

Function TStreamHelper.ReadWideChars(count: Integer) : WideString;
Begin
  SetLength(Result, count);
  Read(PWideChar(Result)^, count * 2);
End;

{$ifdef VER140}{$ENDREGION}{$endif}
Zum speichern eines Records verwende ich dann folgende Implementation:
Delphi-Quellcode:
  PTestData = ^TTestData;
  TTestData = record
    MyInteger : Integer;
    MyString : AnsiString;
    MyWString : WideString;
    MyIntArray : Array of Integer;
    MyRecordArray : Array of PTestData;
    procedure SaveToStream(Stream: TStream);
  end;

implementation

procedure TTestData.SaveToStream(Stream: TStream);
var
  i: Integer;
begin
  Stream.WriteInteger(MyInteger);
  Stream.WriteAString(MyString);
  Stream.WriteWString(MyWString);

  Stream.WriteInteger(length(MyIntArray));
  Stream.Write(MyIntArray[0], length(MyIntArray) * SizeOf(MyIntArray[0]));

  Stream.WriteInteger(length(MyRecordArray));
  for i := 0 to high(MyRecordArray) do
    MyRecordArray[i]^.SaveToStream(Stream);
end;

procedure TTestData.LoadFromStream(Stream: TStream);
var
  i: Integer;
begin
  MyInteger := Stream.ReadInteger;
  MyString := Stream.ReadAString;
  MyWString := Stream.ReadWString;

  SetLength(MyIntArray, Stream.ReadInteger);
  Stream.Read(MyIntArray[0], length(MyIntArray) * SizeOf(MyIntArray[0]));

  SetLength(MyRecordArray, Stream.ReadInteger);
  for i := 0 to high(MyRecordArray) do
    MyRecordArray[i]^.LoadFromStream(Stream);
end;
Das sieht nicht nur um einiges ordentlicher aus, sondern ist auch noch schnell programmiert und viel sicherer.
Björn Zeutzheim
Codename: Performancepumpe
  Mit Zitat antworten Zitat
Antwort Antwort

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:37 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz