AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein GUI-Design mit VCL / FireMonkey / Common Controls Delphi Problem beim Lesen (und schreiben?) von Stream

Problem beim Lesen (und schreiben?) von Stream

Ein Thema von e-gon · begonnen am 13. Apr 2021 · letzter Beitrag vom 14. Apr 2021
Antwort Antwort
Seite 1 von 2  1 2   
e-gon

Registriert seit: 7. Jul 2003
Ort: Stuttgart
154 Beiträge
 
Delphi 6 Enterprise
 
#1

Problem beim Lesen (und schreiben?) von Stream

  Alt 13. Apr 2021, 11:19
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:
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;
Das Öffnen und Speichern ist darüber verwirklicht:
Delphi-Quellcode:
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;
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'.

Was mache ich falsch?

Gruß
e-gon
  Mit Zitat antworten Zitat
Andreas13

Registriert seit: 14. Okt 2006
Ort: Nürnberg
439 Beiträge
 
Delphi XE5 Professional
 
#2

AW: Problem beim Lesen (und schreiben?) von Stream

  Alt 13. Apr 2021, 12:28
Du mußt auch beim LeseninpStream.Position:= 0; setzen.
Gruß, Andreas
Wenn man seinem Nächsten einen steilen Berg hinaufhilft, kommt man selbst dem Gipfel näher.
John C. Cornelius
  Mit Zitat antworten Zitat
e-gon

Registriert seit: 7. Jul 2003
Ort: Stuttgart
154 Beiträge
 
Delphi 6 Enterprise
 
#3

AW: Problem beim Lesen (und schreiben?) von Stream

  Alt 13. Apr 2021, 12:35
Hallo Andreas,

vielen Dank für die schnelle Antwort. Ich habe nun auch in DecompressStream inpStream.Position:= 0; gesetzt. Leider hat sich an dem Problem nichts geändert.

Gruß
e-gon
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
2.830 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#4

AW: Problem beim Lesen (und schreiben?) von Stream

  Alt 13. Apr 2021, 12:41
fs:= TFileStream.Create(FileName, fmCreate); // in procedure TForm1.ProjektOpen
Zitat:
fmCreate - Create a file with the given name. If a file with the given name exists, override the existing file and open it in write mode.
Du überschreibst beim Öffnen die Datei. Die ist leer. Prüfe mal fs.Size.
Die sollte ja größer null sein, wenn richtig eingelesen.

Probiere es doch mal mit fmOpenRead.
  Mit Zitat antworten Zitat
e-gon

Registriert seit: 7. Jul 2003
Ort: Stuttgart
154 Beiträge
 
Delphi 6 Enterprise
 
#5

AW: Problem beim Lesen (und schreiben?) von Stream

  Alt 13. Apr 2021, 12:48
Hallo TiGü,

Du hast natürlich recht! Ich habe mir die Datei damit überschrieben. Da sucht man stundenlang nach einem Fehler und findet derartige Schnitzer dennoch nicht...

Leider besteht das Problem immer noch. Könnte das auch mit BMPLogo.SaveToStream(st); zusammenhängen? Überschreibt das evtl. den zuvor eingefügten String wieder?

Gruß
e-gon
  Mit Zitat antworten Zitat
e-gon

Registriert seit: 7. Jul 2003
Ort: Stuttgart
154 Beiträge
 
Delphi 6 Enterprise
 
#6

AW: Problem beim Lesen (und schreiben?) von Stream

  Alt 13. Apr 2021, 15:18
stahli hatte mal ein ähnliches Problem (siehe https://www.delphipraxis.net/107713-...nd-stream.html)

Ich werde es mal auf diese Art versuchen...
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.079 Beiträge
 
Delphi 10.3 Rio
 
#7

AW: Problem beim Lesen (und schreiben?) von Stream

  Alt 13. Apr 2021, 15:23
Binde doch der einfachkeit halber .zip support ein.
Also externe Daten zippen & dann im temp entzippen/verwenden.
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
e-gon

Registriert seit: 7. Jul 2003
Ort: Stuttgart
154 Beiträge
 
Delphi 6 Enterprise
 
#8

AW: Problem beim Lesen (und schreiben?) von Stream

  Alt 13. Apr 2021, 15:35
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...
  Mit Zitat antworten Zitat
Delphi.Narium

Registriert seit: 27. Nov 2017
1.909 Beiträge
 
Delphi 7 Professional
 
#9

AW: Problem beim Lesen (und schreiben?) von Stream

  Alt 13. Apr 2021, 15:51
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.
  Mit Zitat antworten Zitat
BerndS

Registriert seit: 8. Mär 2006
Ort: Jüterbog
204 Beiträge
 
Delphi 10.4 Sydney
 
#10

AW: Problem beim Lesen (und schreiben?) von Stream

  Alt 13. Apr 2021, 16:20
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;
Bernd
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:05 Uhr.
Powered by vBulletin® Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf