Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   In Stream schreiben und lesen ? (https://www.delphipraxis.net/116138-stream-schreiben-und-lesen.html)

madina 24. Jun 2008 07:38


In Stream schreiben und lesen ?
 
Hallo an alle,

ich habe ein TClientDataSet mit den Feldern:
1.AutoInc (Integer), 2.LandName (String), 3. TIcon (Blob): mit fester Größe
und will den 3.TIcon mit Icons (Typ Blob) füllen.

Schreiben eines Icons in das Feld TIcon wie folgt kein Problem:
Delphi-Quellcode:
begin
  Stream:= nil;
  try
    // CreateStream
    Stream:= TMemoryStream.Create;
    frmMain.CDS_Laden(cdsLand, '\Land.dat');

    for i:=0 to 240 do
      begin
        frmMain.ilFlaggen.GetIcon(i, icBild);
        // SaveImageToStream
        icBild.SaveToStream(Stream);
        Stream.Position:= i; // ist richtig ????

        cdsLand.Insert;
          cdsLand['sLand'] := cbLand.Items[i]; // LandName eintragen
          // LoadBlobFieldFromStream
          TBlobField(cdsLand.FieldByName('blbFahne')).LoadFromStream(Stream); // Icon eintragen
        cdsLand.Post;
      end
  except
    Stream.Free;
    raise;
  end;
  Stream.Free;
end;
Fehler: beim Lesen wie kann ich die einzelenen Icons (Einträge) aus Stream lesen oder ist das Stream wie Felder ansprechbar ?:

Delphi-Quellcode:
begin
  Stream:= nil;
  try
    // CreateStream
    Stream:= TMemoryStream.Create;

    // DatenLesen
    TBlobField(cdsLand.FieldByName('blbFahne')).SaveToStream(Stream);

    Stream.Position:= 10; // ist richtig ???
//    Stream.Seek(0, soFromCurrent);

    icBild.LoadFromStream(Stream);
    Image1.Picture.Assign(icBild);
  except
    Stream.Free;
    raise;
  end;
  Stream.Free;
end;

sirius 24. Jun 2008 07:45

Re: In Stream schreiben und lesen ?
 
Wenn du mehrere Icons im Stream speichern willst, kannst du nicht die Position jedesmal zurücksetzen. Dann überschreibst du doch dein letztes Icon.
Du müsstest die entweder die Größe des Icons mit im Stream speichern oder du hast eine konstante, feste Größe.

madina 25. Jun 2008 07:23

Re: In Stream schreiben und lesen ?
 
Hallo,

mir ist leider immer noch nicht klar wie ich die Icons als Blob in die TClientDataSet schreiben und wie ich dies lesen soll zumindest bei den von mir angegebenen Source klappt dies nicht.

Frage ist wie ich die Größe des gleich größigen Icons beim lesen bestimme und wie ich den Offset erhöhe bitte um ein Beispiel.

mfg

guidok 25. Jun 2008 13:38

Re: In Stream schreiben und lesen ?
 
Schau doch mal bei Delphi Treff Tutorial - Streams da erfährst du einiges über den Umgang mit Streams.

Grundsätzlich ist es bei Streams so, dass du KEIN Datenformat mit abspeicherst, d.h. es wird einfach ein Byte nach dem anderen abgelegt. Was du dann draus machst ist dir überlassen.

Ein Beispiel:

Du willst einen String in einen Stream schreiben, dann schreibst du zunächst die Größe des Strings in den Stream und anschließend den String selbst.

Beim Lesen liest du zuerst die am Anfang des Streams stehende Länge ein und anschließend weißt du wieviele Byte an Daten noch für den String folgen und gelesen werden müssen.

In deinem Fall (wenn ich das richtig verstanden habe) schreibst du als erstes die Anzahl Icons in den Stream und danach ein Icon nach dem anderen. Das geht so nur, wenn die Größe der Icons fest steht und konstant ist.

Zum Lesen, als erstes die Anzahl der Icons aus dem Stream lesen und dann blockweise (Blockgröße = Icongröße) ein Icon nach dem anderen.

guidok 25. Jun 2008 13:48

Re: In Stream schreiben und lesen ?
 
Zitat:

Zitat von guidok
Schau doch mal bei Delphi Treff Tutorial - Streams da erfährst du einiges über den Umgang mit Streams.

Grundsätzlich ist es bei Streams so, dass du KEIN Datenformat mit abspeicherst, d.h. es wird einfach ein Byte nach dem anderen abgelegt. Was du dann draus machst ist dir überlassen.

Ein Beispiel:

Du willst einen String in einen Stream schreiben, dann schreibst du zunächst die Größe des Strings in den Stream und anschließend den String selbst.

Beim Lesen liest du zuerst die am Anfang des Streams stehende Länge ein und anschließend weißt du wieviele Byte an Daten noch für den String folgen und gelesen werden müssen.

In deinem Fall (wenn ich das richtig verstanden habe) schreibst du als erstes die Anzahl Icons in den Stream und danach ein Icon nach dem anderen. Das geht so nur, wenn die Größe der Icons fest steht und konstant ist.

Zum Lesen, als erstes die Anzahl der Icons aus dem Stream lesen und dann blockweise (Blockgröße = Icongröße) ein Icon nach dem anderen.

Der Vollständigkeit halber, falls die Größe der Icons (oder irgendwelcher Daten) variabel ist, dann sieht dein Stream folgendermaßen aus:

Anzahl der Icons im Stream
Größe des ersten Icons
Daten des ersten Icons
Größe des zweiten Icons
Daten des zweiten Icons
...
Größe des letzten Icons
Daten des letzten Icons

sirius 25. Jun 2008 13:54

Re: In Stream schreiben und lesen ?
 
Mein Vorschlag (ungetestet) wäre wie folgt:
Du baust dir deinen Stream aus mehreren einzelnen Streams (welche den einzelnen Icons entsprechen) zusammen und speicherst vorher immer noch die Länge des folgenden Icons.

Delphi-Quellcode:
var c:cardinal;
    tempStream:TMemorytsream;
begin
  Stream:= TMemoryStream.Create;
  tempStream:=TMemorystream.Create;
  try
    frmMain.CDS_Laden(cdsLand, '\Land.dat');

    for i:=0 to 240 do
      begin
        frmMain.ilFlaggen.GetIcon(i, icBild);
        // SaveImageToStream
        tempstream.clear;
        icBild.SaveToStream(tempStream);
        c:=tempstream.size;
        stream.write(c,4); //Größe des IconStreams speichern
        tempstream.seek(0,sofrombeginnig);
        stream.copyfrom(tempstream,c); //IconStream kopieren / anhängen
       
        cdsLand.Insert;
          cdsLand['sLand'] := cbLand.Items[i]; // LandName eintragen
          // LoadBlobFieldFromStream
          TBlobField(cdsLand.FieldByName('blbFahne')).LoadFromStream(Stream); // Icon eintragen
        cdsLand.Post;
      end;
  finally
    Stream.free;
    tempstream.free;
  end;  

end;
 


begin
  Stream:= TMemoryStream.Create;
  tempStream:=TMemorystream.Create;

  try
     
    //warum hier keine Schleife?   
 
    // DatenLesen
    TBlobField(cdsLand.FieldByName('blbFahne')).SaveToStream(Stream);
    Stream.seek(0,sofrombeginnig);
    Stream.read(c,4); //Länge des ersten/nächsten Icons lesen
    tempstream.clear;
    tempstream.copyfrom(stream,c); //Icon rauskopieren
   
    icBild.LoadFromStream(tempStream);
    Image1.Picture.Assign(icBild);
  finally
    Stream.Free;
    tempstream.free;
  end;
end;

DP-Maintenance 25. Jun 2008 15:42

DP-Maintenance
 
Dieses Thema wurde von "Matze" von "Programmieren allgemein" nach "Sonstige Fragen zu Delphi" verschoben.
Delphi-Frage

madina 26. Jun 2008 08:36

Re: In Stream schreiben und lesen ?
 
Hallo,

bitte um Sourcecode:

1. ist dies überhaupt richtig beim Schreiben ???

Delphi-Quellcode:
cdsLand.Insert;
  cdsLand['sLand'] := cbLand.Items[i]; // LandName eintragen
  // LoadBlobFieldFromStream
  TBlobField(cdsLand.FieldByName('blbFahne')).LoadFromStream(Stream); // Icon eintragen (4 Byte).
cdsLand.Post;
ich habe den Eindruck, daß bei jedem Schleifendurchlauf schreibe ich den kompleten Stream (von 0 bis zum aktuellen Schleifenanzahl) in jedem TClientDataSet Datensatz und dadurch bläht sich TClientDataSet auf ??

2. ist es möglich durch jeden Schleifendurchgang den Stream um die Icongröße zu vergrößern und zwar wie ? und nicht am Anfang, wo ich vielleicht nicht weiß wieviele Icons ich da hineinpacke.

3. wie sieht die Schleife mit dem Lesen der einzelnen Icons aus dem TClientDataSet ?

mfg

guidok 26. Jun 2008 08:47

Re: In Stream schreiben und lesen ?
 
Ohne jetzt genauer auf deinen Code einzugehen:

1. Mit LoadFromStream lädst du den gesamten Stream.

Ich hatte das selbe Problem einmal, als ich mehrere Bilder in einen Stream schreiben wollte. Ich habe mir dazu einen temporären MemoryStream erzeugt, in dem ich das Bitmap mit LoadFromStream, bzw. WriteToStream gepackt habe (genau ein Bitmap). Zusätzlich hatte ich einen FileStream in den, Bitmap für Bitmap, der temporäre Stream geschrieben wurde (natürlich mit den entsprechenden Größenangaben des jeweiligen Bitmaps, damit auch wieder zurück gelesen werden kann).

2. Natürlich ist das möglich, sobald du verstanden hast, wie der Stream funktioniert, dann wirst du das auch umsetzen können, in aller Kürze:

Die Anzahl deiner Icons im Stream steht in den ersten vier Byte des Stream (LongInt), danach folgt ein Icon. Nun musst du dir zunächst merken, wo du aktuell im Stream stehst. Du setzt die Streamposition auf den Anfang (auf die Anzahl der Icons) und schreibst die neue Anzahl in den Stream. Danach setzt du die Streamposition wieder auf den gemerkten Wert (auf das Ende des zuletzt gespeicherten Icons). Da deine Icons alle gleich groß sind bestünde auch die Möglichkeit die Position aus der Anzahl und Größe der Icons zu errechnen, ganz wie du willst.

3. Kann ich jetzt nichts dazu sagen, weil ich mich nicht näher mit beschäftigt habe.

guidok 26. Jun 2008 08:55

Re: In Stream schreiben und lesen ?
 
Ich hab den Code grade wiedergefunden. In den Stream werden in diesem Fall mehrere Datensätze vom Typ TCard geschrieben. Der besteht unter anderem aus einem Bitmap und mehreren Strings.


Delphi-Quellcode:

type
  TCard = record
    Bitmap: TBitmap;  //Kartenbild
    Name: String;      //Kartenname
    Description: String;//Kartenbeschreibung
    Kind: String;      //Kartentyp
    Action: String;    //Auszuführende Aktionen
  end;


procedure TCardset.ReadFromFile(Filename: string);
var
  lFs: TFileStream;
  lMs: TMemoryStream;
  lLen: Longint;
  lI: Integer;
begin
  Free;
  lFs:=TFileStream.Create(Filename,fmOpenRead);
  lMs:=TMemoryStream.Create;
  try
    //Länge des Cardset
    lFS.Read(lLen,SizeOf(lLen));
    SetLength(Cards,lLen);
    //Die Daten des Cardset speichern
    for lI := 0 to Length(Cards) - 1 do begin
      //Bitmap
      lMs.Clear;
      lFs.Read(lLen,SizeOf(lLen));
      lMs.CopyFrom(lFs,lLen);
      Cards[lI].Bitmap:=TBitmap.Create;
      lMs.Position:=0;
      Cards[lI].Bitmap.LoadFromStream(lMs);
      //Strings
      lFs.Read(lLen,SizeOf(lLen));
      SetLength(Cards[lI].Name,lLen);
      lFs.Read(PChar(Cards[lI].Name)^,lLen);
      lFs.Read(lLen,SizeOf(lLen));
      SetLength(Cards[lI].Kind,lLen);
      lFs.Read(PChar(Cards[lI].Kind)^,lLen);
      lFs.Read(lLen,SizeOf(lLen));
      SetLength(Cards[lI].Description,lLen);
      lFs.Read(PChar(Cards[lI].Description)^,lLen);
      lFs.Read(lLen,SizeOf(lLen));
      SetLength(Cards[lI].Action,lLen);
      lFs.Read(PChar(Cards[lI].Action)^,lLen);
    end;
  finally
    lFS.Free;
    lMs.Free;
  end;
end;

procedure TCardset.SaveToFile(Filename: string);
var
  lFs: TFileStream;
  lMs: TMemoryStream;
  lLen: Longint;
  lI: Integer;
begin
  lFs:=TFileStream.Create(Filename,fmCreate);
  lMs:=TMemoryStream.Create;
  try
    //Länge des Cardset
    lLen:=Length(Cards);
    lFs.Write(lLen,SizeOf(lLen));
    //Die Daten des Cardset speichern
    for lI := 0 to Length(Cards) - 1 do begin
      //Bitmap
      lMs.Clear;
      Cards[lI].Bitmap.SaveToStream(lMs);
      lMs.Position:=0;
      lLen:=lMs.Size;
      lFs.Write(lLen,SizeOf(lLen));
      lFs.CopyFrom(lMs,lLen);
      //Strings
      lLen:=Length(Cards[lI].Name);
      lFs.Write(lLen,SizeOf(lLen));
      lFs.Write(PChar(Cards[lI].Name)^,lLen);
      lLen:=Length(Cards[lI].Kind);
      lFs.Write(lLen,SizeOf(lLen));
      lFs.Write(PChar(Cards[lI].Kind)^,lLen);
      lLen:=Length(Cards[lI].Description);
      lFs.Write(lLen,SizeOf(lLen));
      lFs.Write(PChar(Cards[lI].Description)^,lLen);
      lLen:=Length(Cards[lI].Action);
      lFs.Write(lLen,SizeOf(lLen));
      lFs.Write(PChar(Cards[lI].Action)^,lLen);
    end;
  finally
    lFs.Free;
    lMs.Free;
  end;
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:39 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