Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Records verwalten mit TList und TStream (https://www.delphipraxis.net/49830-records-verwalten-mit-tlist-und-tstream.html)

Panthrax 16. Jul 2005 20:14


Records verwalten mit TList und TStream
 
Salut.

Ich möchte mir ein Objekt zum Verwalten von Records, deren Quelle ein Stream ist, schaffen.

Im ersten Schritt habe ich mir die Klasse TList genommen und an sie die Information über die Recordgröße geknüpft. Fertig war meine Klasse TRecordList.

Im zweiten Schritt möchte ich erreichen, dass diese Liste ein TStream-Objekt als Standarddatenquelle nutzt. Mit der Eigenschaft Items[Index] soll dann auf jeden Record zugegriffen werden können. Ist der Record noch nicht im Speicher soll er aus dem Stream gelesen und in den Speicher kopiert werden. In jedem Fall gibt Items dann einen Pointer auf den Record im Speicher zurück. (Das vertraute Verhalten von TList.)

Dabei stellt sich mir folgendes Problem: Wie kann ich sicherstellen, dass die Records im Speicher gleich denen im Stream sind? Denn die Anwendung führt an anderer Stelle möglicherweise Schreib-Lese-Operationen an dem Stream durch.

Ich habe mir überlegt, wenn es dasselbe Objekt handhaben würde, bekäme es die Schreib-Lese-Operationen mit, und könnte geschriebene Records aus dem Speicher entfernen. (Besteht noch Lesebedarf werden sie ja erneut in den Speicher geholt.) Folglich brauche ich also ein Objekt, das TStream und TList zugleich ist. Das aber geht in Delphi nicht. Was kann ich tun? Hat jemand eine kozetionell andere Lösung? Ich bin für alles offen.

Noch ein Hinweis: Interfaces kommen nicht in Frage. Im Gesamtkontext gibt es zuviele Delphi-Routinen, die ich benutzen möchte, die TList- und TStream-Objekte erwarten.

Panthrax.

Hier noch etwas Quelltext zum Verständnis:
Delphi-Quellcode:
type
  { TRecordList
  Hier wird nur die Möglichkeit geschaffen, die Information über die Recordgröße bei der Liste zu hinterlegen. }
  TRecordList = class(TList)
    private
    FRecordSize: Integer;

    published
    property RecordSize: Integer read FRecordSize write FRecordSize;

    constructor Create(RecordSize: Integer);
  end;

constructor TRecordList.Create(RecordSize: Integer);
begin
  FRecordSize:=RecordSize;
end;

type
  { TRecordListStreamStreamBounded
  Diese Klasse ist nur eine Beispielimplementierung um zu demonstrieren, was die Eigenschaft Items tun soll, wenn ein Record nachgrfragt wird. }
  TRecordListStreamStreamBounded = class(TRecordList)
    private
    FBoundedStream: TStream;
    function GetItems(Index: Integer):Pointer;
    procedure SetItems(Index: Integer; const Value: Pointer);

    public
    property Items[Index: Integer]:Pointer read GetItems write SetItems; default;

    published
    constructor Create(BoundedStream: TStream);
    { Methoden die Records aus dem Speicher zu entfernen und zu speichern gibt es natürlich auch noch... }
  end;

constructor TRecordListStreamStreamBounded.Create(BoundedStream: TStream);
begin
  FBoundedStream:=BoundedStream;
end;

function TRecordListStreamStreamBounded.GetItems(Index: Integer): Pointer;
var
  RecordPtr: Pointer;
begin
  Result:=inherited Items[Index];
  if Result = NIL then with BoundedStream do
  begin
    GetMem(RecordPtr,RecordSize);
    try
      Seek(soFromBeginning,Index*RecordSize);
      Read(RecordPtr^,RecordSize);
        // Auf Read(...) <> RecordSize zu prüfen spar' ich mir jetzt mal.
    except
      FreeMem(RecordPtr,RecordSize);
    end;
  end;
end;

procedure TRecordListStreamStreamBounded.SetItems(Index: Integer;
  const Value: Pointer);
begin
  inherited Items[Index]:=Value;
end;

DGL-luke 16. Jul 2005 20:39

Re: Records verwalten mit TList und TStream
 
da komme ich auf folgende überlegungen:

man könnte daraus singletostream machen, welches

1. an die position des records springt, sprich alle werte der liste addiert, bis sie beim gesuchten record angekommen ist
2. den record schreibt
3. den record freigibt, seine größe aber hält

sowie singlefromstream, welches

1. an die richtige position springt
2. aus dem stream lädt
3. die größe in die liste einträgt

und wo liegt nun dein problem?

Robert_G 16. Jul 2005 20:44

Re: Records verwalten mit TList und TStream
 
Du brauchst einfach nur die gleiche Instanz der Liste dort wo du die Liste verwendet hat und da wo du den Stream verwendest, ersetzen ihn gegen die Liste.
Erst beim Speichern/Lesen wird der Strream interessant. So klingt mir das nach zuviel Friemelei. ;)

Panthrax 16. Jul 2005 21:00

Re: Records verwalten mit TList und TStream
 
@DGL-Luke

Hm. - Ich hab' gerade ein geräzelt, was Du meinst, bin aber zu keiner Lösung gekommen. Bitte was ist SingleToStream und StreamToSingle?

Vielleicht noch einige Worte zum Hintergrund: Die Record-Dateien sind recht groß im Verhältnis zu den Recordgrößen. Wenn auf die Records zugegriffen wird, betrifft dies meist nur wenige. Mit dem vorhalten im Speicher wird also eine Art Caching angestrebt.

Und das Problem besteht darin, dass die Daten einmal als TStream-Objekt (mit all seinen Funktionen)und ein anderes Mal als TList-Objekt (mit all seinen Funktionen) betrachtet werden.

Es gibt Routinen die erwarten Parameter in dieser Weise:
Delphi-Quellcode:
procedure SaveToStream(Stream: TStream);
function EvalRecords(RecordList: TRecordList);
In beiden Fällen sind die zu verwaltenden Records als die Daten dahinter gefragt.

Panthrax.

DGL-luke 16. Jul 2005 21:10

Re: Records verwalten mit TList und TStream
 
die funktionen "singletostream" und "singlefromstream" sollst du selbst implementieren, und zwar, um einen einzelnen record zu süpeichern und einen einzelnen record zu laden - was ja offenabr dein ziel ist.

und wenn du meinen vorschlag nicht verstehst, dann kann ich dir vielleicht weiterhelfen, wenn du mir sagst, wie dein kenntnisstand bei streams ist.

@_G: häh? wir sind doch gerade beim speichern und laden, was erzählst du jetzt vom ersetzen? :|

Robert_G 16. Jul 2005 21:21

Re: Records verwalten mit TList und TStream
 
Zitat:

Zitat von DGL-luke
@_G: häh? wir sind doch gerade beim speichern und laden, was erzählst du jetzt vom ersetzen? :|

Ich glaube, dass er leiber den Teil der Liste, der für ihn interessant ist als das gleiche Object (Object== LIst, alles klar? ) überall verwendet. Somit wären Änderungen überall sichtbar.

Panthrax 16. Jul 2005 21:39

Re: Records verwalten mit TList und TStream
 
Mein Kenntnisstand bei Streams ist, dass ich gedenke TWinSocketStream zu überschreiben um von der Verbindung gelesene Streamdaten vorzuhalten, damit die Liste auf diesen Daten arbeiten kann. Werden Daten in über das Stream-Objekt Daten versendet, betrifft dies möglicherweise auch die Liste. Daher ist es wünschenswert die Stream-Funktionen und die Listen-Funktionen in einem Objekt zu vereinen. Oder eben, da dies in Delphi nicht geht, zwei sehr kooperative Objekte zu schaffen.

Zur Veranschaulichung:
Delphi-Quellcode:
{ eingehender Datenstrom }
+--------+--------+--------+--------+-------<
| Record | Record | Record | Record | ...
+--------+--------+--------+--------+-------<
     |                           { ausgehender Datenstrom }
     |                              +-------+----->
     |                              +-------+----->
     |                                A
     |                                |
+|||||||||||||||||||||||||||||||||||||||||||||||||||+
=   |                                |             =
=   | Lesen (TWinSocketStream)      | Schreiben  =
=   |                                |             =
=   V                               |             =
= +===============================================+ =  
= | TMyTWinSocketStream-Objekt                   | =
= +-----------------------------------------------+ =
= | { Hier gibt es einen Puffer. }                | =
= | { Der hält die Verbindungsdaten bereit, }     |<-----
= | { damit das TRecordListStreamBounded-Objekt } |----->
= | { sie anfordern kann. }                       | =
= +===============================================+ =
=   |                                A            =
=   | Lesen (TMyWinSocketStream)    | Schreiben  =
=   |                                |             =
=   V                               |             =
= +===============================================+ =
= | TRecordListStreamBounded                     | =
= +-----------------------------------------------+<-----
= | { Verwaltung der Liste. }                     |----->
= +===============================================+ =
=                                                  =
+|||||||||||||||||||||||||||||||||||||||||||||||||||+


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:12 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz