![]() |
Problem beim Lesen (und schreiben?) von Stream
Hallo zusammen,
im Moment schreibe ich einen Editor zum Erstellen eines Brettspiel-Spielplans. Da die Autoren den Spielplan möglicherweise nicht an einem Tag erstellen oder den Plan digital weitergeben wollen, erstelle ich gerade eine Speicher- und Ladefunktion. Während der Erstellung erlaube ich dem Autor eigene Bilder (z.B. ein eigenes Logo) einzufügen, für einzelne Elemente die Schriftart einzustellen und auch andere Einstellungen anzupassen. Das alles muss dann natürlich mit abgespeichert werden. Und da diese eigenen Bilder intern als Bitmaps vorliegen, wäre eine Komprimierung beim Speichern sehr sinnvoll. Zur Verwirklichung stopfe ich zunächst alles in ein TMemoryStream und Komprimiere das ganze mit Hilfe von ZLib. Das Packen und Entpacken sieht dann so aus:
Delphi-Quellcode:
Das Öffnen und Speichern ist darüber verwirklicht:
procedure CompressStream(inpStream: TMemoryStream; outStream: TFileStream);
var InpBuf,OutBuf: Pointer; InpBytes, OutBytes: Integer; begin InpBuf:= nil; OutBuf:= nil; try GetMem(InpBuf, inpStream.Size); inpStream.Position:= 0; InpBytes:= inpStream.Read(InpBuf^ inpStream.Size); CompressBuf(InpBuf, InpBytes, OutBuf, OutBytes); outStream.Write(OutBuf^, OutBytes); finally if InpBuf<>nil then FreeMem(InpBuf); if OutBuf<>nil then FreeMem(OutBuf); end; end; procedure DecompressStream(inpStream: TFileStream; outStream: TMemoryStream); var InpBuf,OutBuf: Pointer; OutBytes,sz: Integer; begin InpBuf:= nil; OutBuf:= nil; sz:= inpStream.Size - inpStream.Position; if sz>0 then begin try GetMem(InpBuf, sz); inpStream.Read(InpBuf^, sz); DecompressBuf(InpBuf, sz, 0, OutBuf, OutBytes); outStream.Write(OutBuf^, OutBytes); finally if InpBuf<>nil then FreeMem(InpBuf); if OutBuf<>nil then FreeMem(OutBuf); end; end; outStream.Position:= 0; end;
Delphi-Quellcode:
Theoretisch funktioniert das Speichern (es kommt eine von der Größe her plausieble Datei heraus), aber beim Auslesen des ersten Strings bekomme ich bei st.ReadBuffer(l,SizeOf(l)) den Fehler 'Stream-Lesefehler'.
var
Projektname: string; BMPLogo: TBitmap; // wird bei FormCreate natürlich auch erstellt! Text1: string; Text2: string; Len: Integer; procedure TForm1.ProjektSave(Filename: string); procedure SaveToStream(const s: AnsiString; var st: TMemoryStream); Overload; var l: LongInt; begin l:= Length(s); st.Write(l, SizeOf(l)); if l>0 then st.Write(s[1], l); end; procedure SaveToStream(const i: LongInt; var st: TMemoryStream); Overload; begin st.Write(i, SizeOf(LongInt)); end; var st: TMemoryStream; fs: TFileStream; begin fs:= TFileStream.Create(FileName, fmCreate); st:= TMemoryStream.Create; try SaveToStream(Projektname, st); BMPLogo.SaveToStream(st); SaveToStream(Text1, st); SaveToStream(Text2 ,st); SaveToStream(Len, st); CompressStream(st, fs); finally st.Free; fs.Free; end; end; procedure TForm1.ProjektOpen(Filename: string); function LoadStrFromStream(const st: TMemoryStream): AnsiString; var l: LongInt; begin st.ReadBuffer(l, SizeOf(l)); // -> beim ersten Durchlauf knallt es hier dann SetLength(Result, l); if l>0 then st.ReadBuffer(Result ,l); end; function LoadIntFromStream(const st: TMemoryStream): LongInt; begin st.ReadBuffer(Result, SizeOf(Result)); end; var st: TMemoryStream; fs: TFileStream; begin fs:= TFileStream.Create(FileName, fmCreate); st:= TMemoryStream.Create; try DecompressStream(fs, st); Projektname:= LoadStrFromStream(st); BMPLogo.LoadFromStream(st); Text1:= LoadStrFromStream(st); Text2:= LoadStrFromStream(st); Len:= LoadIntFromStream(st); finally st.Free; fs.Free; end; end; Was mache ich falsch? Gruß e-gon |
AW: Problem beim Lesen (und schreiben?) von Stream
Du mußt auch beim Lesen
Delphi-Quellcode:
setzen.
inpStream.Position:= 0;
Gruß, Andreas |
AW: Problem beim Lesen (und schreiben?) von Stream
Hallo Andreas,
vielen Dank für die schnelle Antwort. Ich habe nun auch in DecompressStream
Delphi-Quellcode:
gesetzt. Leider hat sich an dem Problem nichts geändert.
inpStream.Position:= 0;
Gruß e-gon |
AW: Problem beim Lesen (und schreiben?) von Stream
Delphi-Quellcode:
fs:= TFileStream.Create(FileName, fmCreate); // in procedure TForm1.ProjektOpen
Zitat:
Die sollte ja größer null sein, wenn richtig eingelesen. Probiere es doch mal mit fmOpenRead. |
AW: Problem beim Lesen (und schreiben?) von Stream
Hallo TiGü,
Du hast natürlich recht! Ich habe mir die Datei damit überschrieben. :lol: Da sucht man stundenlang nach einem Fehler und findet derartige Schnitzer dennoch nicht... Leider besteht das Problem immer noch. Könnte das auch mit
Delphi-Quellcode:
zusammenhängen? Überschreibt das evtl. den zuvor eingefügten String wieder?
BMPLogo.SaveToStream(st);
Gruß e-gon |
AW: Problem beim Lesen (und schreiben?) von Stream
stahli hatte mal ein ähnliches Problem (siehe
![]() Ich werde es mal auf diese Art versuchen... |
AW: Problem beim Lesen (und schreiben?) von Stream
Binde doch der einfachkeit halber .zip support ein.
Also externe Daten zippen & dann im temp entzippen/verwenden. |
AW: Problem beim Lesen (und schreiben?) von Stream
Hallo KodeZwerg,
Du meinst einen temporären Ordner erstellen, dort alles getrennt speichern, den kompletten Ordner zippen und diesen dann wieder löschen? Das hätte natürlich den Vorteil, dass man zur Not auch ohne den Editor an die Daten herankäme. Andererseits stehe ich nicht so auf Temporäre Dateien und außerdem ist die Festplatte doch langsamer als der Arbeitsspeicher. Muss mal in mich gehen... |
AW: Problem beim Lesen (und schreiben?) von Stream
Für die Arbeit mit ZIP-Archiven braucht man keinen temporären Ordner oder temporäre Dateien. Man kann auch einen Stream direkt ins ZIP packen.
Auf der Festplatte entsteht nur die ZIP-Datei. |
AW: Problem beim Lesen (und schreiben?) von Stream
Beim Einlesen der Strings sollte nicht Result, sondern Result[1] verwendet werden, da hier der Zeichenpuffer des Ansistrings beginnt.
Delphi-Quellcode:
function LoadStrFromStream(const st: TMemoryStream): AnsiString;
var l: LongInt; begin st.ReadBuffer(l, SizeOf(l)); // -> beim ersten Durchlauf knallt es hier dann SetLength(Result, l); if l>0 then st.ReadBuffer(Result[1] ,l); end; |
AW: Problem beim Lesen (und schreiben?) von Stream
Das erste Zeichen des Puffers ist 0 mund nicht 1. Der Positionszeiger muss auf 0 gesetzt werden:
Delphi-Quellcode:
Gruß, Andreas
function LoadStrFromStream(Const St: TMemoryStream): AnsiString;
var Len: LongInt; begin St.Position:= 0; St.ReadBuffer(Len, SizeOf(Len)); SetLength(Result, Len); If Len > 0 Then St.ReadBuffer(Result[0] , Len*SizeOf(Result[0])); end; |
AW: Problem beim Lesen (und schreiben?) von Stream
Bei einem Shortstring ist Index 0 das Längenbyte und danach kommen die Zeichen. Bei Strings und Ansistrings beginnt der Puffer ebenfalls bei 1.
Teste es mal im Debugger. Ich habe es natürlich zuvor getestet. |
AW: Problem beim Lesen (und schreiben?) von Stream
Du hast recht, BerndS: Ich habe den AnsiString nicht beachtet...:oops:
Andreas |
AW: Problem beim Lesen (und schreiben?) von Stream
Ganz allgemein könnte man es evtl. so schreiben:
Delphi-Quellcode:
damit das Lesen für jedwenden BufferType funktioniert.
...
If Len > 0 Then St.ReadBuffer(Result[Low(Result)] , Len*SizeOf(Result[Low(Result)])); Andreas |
AW: Problem beim Lesen (und schreiben?) von Stream
Hallo,
vielen Dank für Eure ganzen Antworten! Ein kleines Problem habe ich da allerdings noch: Weiß jemand wie ich die Einstellungen eines Font abspeichere? Font.SaveToStream gibt es leider nicht. Und auch Stream.WriteComponent will nicht funktionieren... Gruß e-gon |
AW: Problem beim Lesen (und schreiben?) von Stream
Schau dir mal TReader und TWriter an ... das nimmt auch Delphi, um die DFM zu speichern (wobei hier das Binär raus kommt, aber in Text konvertriert werden kann)
Und es gibt auch Mapper für XML oder JSON, um Objekte zu (de)serialisieren.
Delphi-Quellcode:
funktioniert mit allen Delphi-Strings (außer ShortString)
ReadOrWrite(Pointer(S), Length(S)*StringElementSize(S));
aber generell ist es besser statt Pointer das passende PChar/PAnsiChar/PWideChar zu verwenden.
Delphi-Quellcode:
und z.B. bei typlosen VAR-Parametern noch ein ^ hinten dran, an den Cast.
ReadOrWrite(PChar(S), Length(S)*SizeOf(Char)); // String
ReadOrWrite(PAnsiChar(A), Length(A){*SizeOf(AnsiChar)}); // AnsiString ReadOrWrite(PWideChar(U), Length(U)*SizeOf(WideChar)); // UnicodeString und WideString |
AW: Problem beim Lesen (und schreiben?) von Stream
Zitat:
Zitat:
.zip kann vollkommen per TStream abgewickelt werden, laden speichern löschen whatever. ob nun text bilder oder whatever. ich finde es ist die einfachste möglichkeit damit umzugehen, da die eigentliche datei (das archiv) eh mitgegeben werden muss. (ob nun zip zlib whatever) eine font ist meist eine ttf datei, die einfach mit ins archiv, fertig. |
AW: Problem beim Lesen (und schreiben?) von Stream
Hallo zusammen,
vielen lieben Dank für die ganzen Antworten! Ich muss das jetzt erstmal alles ausprobieren und verstehen. Bis evtl. noch Fragen aufkommen lösche ich die Markierung zur offenen Frage. Danke nochmals an alle! :thumb: Gruß e-gon |
AW: Problem beim Lesen (und schreiben?) von Stream
Vielleicht anstelle einer Menge von Dateien eine einzelne Datei schreiben/lesen: eine SQLite Datenbank.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:23 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 by Thomas Breitkreuz