Hallo Leute!
Gleich vorweg: Ich habe noch nicht oft mit Streams gearbeitet.
Ich möchte per Stream verschiedene Daten in eine Datei schreiben und wieder lesen können.
Im Detail sind die Daten Klassen, welche irgendwelche Informationen enthalten (Beschreibung, etc...).
Die Klassen kennen sich untereinander nicht. Somit muss ich die Daten im Stream anhand von Headern identifizieren können.
In meiner Vorstellung sieht das so aus:
|_HeaderA_|_DataA___________|_HeaderB_|_DataB_____ ______|_HeaderC_|_DataC___________|
Nur leider habe ich keine Idee, wie ich das umsetzen kann
So sieht mein Testframe aus:
Delphi-Quellcode:
unit FmStreamOperations;
interface
uses
Winapi.Windows,
Winapi.Messages,
System.SysUtils,
System.Variants,
System.Classes,
Vcl.Graphics,
Vcl.Controls,
Vcl.Forms,
Vcl.Dialogs,
Vcl.StdCtrls;
type
(*
This is the first record that should be saved to a file
most important properties:
@ version field that can be interpreted from reader classes
@ conentlen field when the record ends and the next record begins
NOTE: packed record because the memory alignment of regular records are
subject to change between releases
*)
TDummyHeaderA =
packed record
// after structure changes increment this
Version: Integer;
// position of begin of content
Pos: Integer;
// Integer should be enough to prevent to low allocation for the content
Len: LongInt;
// do not use dynamic length; ShortString (String[255]) instead of String
HeaderType: ShortString;
end;
(*
This is the second record that should be saved to a file
most important properties:
@ version field that can be interpreted from reader classes
@ conentlen field when the record ends and the next record begins
NOTE: packed record because the memory alignment of regular records are
subject to change between releases
*)
TDummyHeaderB =
packed record
// after structure changes increment this
Version: Integer;
// position of begin of content
Pos: Integer;
// Integer should be enough to prevent to low allocation for the content
Len: Integer;
// do not use dynamic length; ShortString (String[255]) instead of String
HeaderType: ShortString;
end;
(*
This is the third record that should be saved to a file
most important properties:
@ version field that can be interpreted from reader classes
@ conentlen field when the record ends and the next record begins
NOTE: packed record because the memory alignment of regular records are
subject to change between releases
*)
TDummyHeaderC =
packed record
// after structure changes increment this
Version: Integer;
// position of begin of content
Pos: Integer;
// Integer should be enough to prevent to low allocation for the content
Len: Integer;
// do not use dynamic length; ShortString (String[255]) instead of String
HeaderType: ShortString;
end;
(*
This is a dummy class for testing the header TDatasetHeaderA
*)
TDummyA =
class(TPersistent)
private
FValueA: Integer;
FValueB:
string;
FValueC: Boolean;
public
constructor Create;
destructor Destroy;
override;
property ValueA: Integer
read FValueA
write FValueA;
property ValueB:
string read FValueB
write FValueB;
property ValueC: Boolean
read FValueC
write FValueC;
end;
(*
This is a dummy class for testing the header TDatasetHeaderB
*)
TDummyB =
class(TPersistent)
private
FValueA: Int64;
FValueB: ShortString;
FValueC: PChar;
public
constructor Create;
destructor Destroy;
override;
property ValueA: Int64
read FValueA
write FValueA;
property ValueB: ShortString
read FValueB
write FValueB;
property ValueC: PChar
read FValueC
write FValueC;
end;
(*
This is a dummy class for testing the header TDatasetHeaderC
*)
TDummyC =
class(TPersistent)
private
FValueA: SmallInt;
FValueB: Char;
FValueC: Double;
public
constructor Create;
destructor Destroy;
override;
property ValueA: SmallInt
read FValueA
write FValueA;
property ValueB: Char
read FValueB
write FValueB;
property ValueC: Double
read FValueC
write FValueC;
end;
(*
Testframe form
*)
TFmTestframe =
class(TForm)
ButtonSave: TButton;
ButtonLoad: TButton;
procedure ButtonSaveClick(Sender: TObject);
procedure ButtonLoadClick(Sender: TObject);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
(*
constants
*)
const C_FILE_EXT = '
bin';
const C_FILE_LOC = '
C:\';
var
FmTestframe: TFmTestframe;
implementation
{$R *.dfm}
procedure TFmTestframe.ButtonLoadClick(Sender: TObject);
var
Stream: TFileStream;
FileName:
string;
HeaderA: TDummyHeaderA;
DataA: TDummyA;
begin
// Try to load TDummyHeaderA & TDummyA from file via stream to the objects
FileName :=
Format('
%s.ExampleFileWrittenWithStream.%s', [C_FILE_LOC, C_FILE_EXT]);
// !! don't forget to check if the file exist and is accessable in production builds
Stream := TFileStream.Create(FileName, fmOpenRead);
try
// Stream.Read(...) <----- ??? What to do here?
finally
FreeAndNil(Stream);
end;
end;
procedure TFmTestframe.ButtonSaveClick(Sender: TObject);
var
Stream: TFileStream;
HeaderA: TDummyHeaderA;
DataA: TDummyA;
FileName:
string;
begin
// Try it with TDummyHeaderA & TDummyA first
// Fill TDummyHeaderA with data
HeaderA.Version := 1;
HeaderA.Pos := 0;
{ replace with start point of the content??? }
HeaderA.Len := 0;
{ replace with the length of the content??? }
HeaderA.HeaderType := '
[Type] Dummy Header A';
// TDummyA is filled with dummy data by the constructor
DataA := TDummyA.Create;
try
// Try to save TDummyHeaderA & TDummyA into file via stream
FileName :=
Format('
%s.ExampleFileWrittenWithStream.%s', [C_FILE_LOC, C_FILE_EXT]);
// !! don't forget to check if the file exist and is accessable in production builds
Stream := TFileStream.Create(FileName, fmCreate);
try
// Stream.Write(HeaderA, ...) <----- ??? What to do here?
// ...
// ..
// .
finally
FreeAndNil(Stream);
end;
finally
FreeAndNil(DataA);
end;
end;
{ TDummyA }
constructor TDummyA.Create;
begin
FValueA := 1;
FValueB := '
DummyA Example Text';
FValueC := True;
end;
destructor TDummyA.Destroy;
begin
inherited;
end;
{ TDummyB }
constructor TDummyB.Create;
begin
FValueA := 9823323232313;
FValueB := '
Dummy B';
FValueC := PChar('
Pointer to string test');
end;
destructor TDummyB.Destroy;
begin
inherited;
end;
{ TDummyC }
constructor TDummyC.Create;
begin
FValueA := -1;
FValueB := '
C';
FValueC := 3.14;
end;
destructor TDummyC.Destroy;
begin
inherited;
end;
end.
Es wäre nett, wenn mir jemand Hilfestellung geben könnte