Einzelnen Beitrag anzeigen

delphinub23

Registriert seit: 27. Okt 2010
Ort: Chemnitz
110 Beiträge
 
Delphi XE3 Professional
 
#1

Daten per Streams in Datei schreiben

  Alt 22. Jul 2014, 10:51
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

Geändert von delphinub23 (22. Jul 2014 um 10:56 Uhr)
  Mit Zitat antworten Zitat