Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: So Jul 13, 2025 18:14

Foren-Übersicht » Programmierung » Allgemein
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 8 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Stream lesen liefert kein ergebnis
BeitragVerfasst: So Feb 27, 2011 13:38 
Offline
DGL Member

Registriert: Mi Jan 05, 2011 14:55
Beiträge: 47
Programmiersprache: Delphi, C++,C
Hallo zusammen
ich hab ein kleines Problem. Ich hab eine Prozedur geschrieben, welche single und string Variable in einen Stream schgreibt. Das Problem ist nur, das wenn ich es auslesen will, überhaupt nichts drinn steht laut delphi. Meine vermutung ist, das es an den singlevariablen liegt hab aber keine Ahnung, wie ich es lösen soll.

Hier mal der Code zum speichern:
Code:
procedure TModelliste.SpeicherInListe;
var
 Stream : TFilestream;
 i : integer;
 Len: LongInt;
begin
 Stream := TFilestream.Create(ExtractFilePath(Application.ExeName)+'\material\models.liste', fmCreate);
  try
   len := length(models);
   Stream.Write(len,sizeof(len));
   for I := 0 to length(models)-1 do
    begin
     Stream.Write(models[i].pX, SizeOf(models[i].pX));

     Stream.Write(models[i].pY, SizeOf(models[i].pY));

     Stream.Write(models[i].pZ, SizeOf(models[i].pZ));

     Stream.Write(models[i].pBreite, SizeOf(models[i].pBreite));

     Stream.Write(models[i].pHoehe, SizeOf(models[i].pHoehe));

     Stream.Write(models[i].pTiefe, SizeOf(models[i].pTiefe));

     Len := Length(models[i].Dateipfad);
     Stream.Write(Len, SizeOf(Len));
     Stream.Write(PChar(models[i].Dateipfad)^, Len);

     Len := Length(models[i].Texturpfad);
     Stream.Write(Len, SizeOf(Len));
     Stream.Write(PChar(models[i].texturpfad)^, Len);
    end;
   finally
    stream.Free;
   end;
end;


und der Code zum lesen:
Code:
procedure TModelliste.LadeAusDatei;
var
 Stream : TFilestream;
 i : integer;
 Len: LongInt;
begin
 if fileexists(ExtractFilePath(Application.ExeName)+'\material\models.liste') = true
  then
   begin
    Stream := TFilestream.Create(ExtractFilePath(Application.ExeName)+'\material\models.liste', fmOpenRead);
    try
     Stream.Read(Len, SizeOf(Len));
     SetLength(Models, Len);
     for I := 0 to length(models) - 1 do
      begin
       models[i] := TModel.create;

       Stream.Read(models[i].pX, SizeOf(models[i].pX));

       Stream.Read(models[i].pY, SizeOf(models[i].pY));

       Stream.Read(models[i].pZ, SizeOf(models[i].pZ));

       Stream.Read(models[i].pBreite, SizeOf(models[i].pBreite));

       Stream.Read(models[i].pHoehe, SizeOf(models[i].pHoehe));

       Stream.Read(models[i].pTiefe, SizeOf(models[i].pTiefe));

       Stream.Read(Len, SizeOf(Len));
       SetLength(models[i].Dateipfad, Len);
       Stream.Read(PChar(models[i].Dateipfad)^, Len);

       Stream.Read(Len, SizeOf(Len));
       SetLength(models[i].Texturpfad, Len);
       Stream.Read(PChar(models[i].texturpfad)^, Len);

       models[i].init(models[i].px,models[i].py,models[i].pz,models[i].Dateipfad, models[i].Texturpfad);
      end;
    finally
     stream.Free;
    end;
  end
   else
    Setlength(models,0);
end;


Ach ja mit integer variablen klappt es übrigens reibungslos.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Feb 27, 2011 15:26 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Also ich vermute mal, dass das Problem an dem PChar liegen wird. Bei Strings ist so etwas nicht einfach nur eine Casten auf den Pointer sondern es kann passieren, dass dabei der ein temporärer Speicherbereich erstellt wird und der String konvertiert wird. Wenn das passiert, dann ließt dein Stream in einen Speicherbereich der direkt wieder gelöscht wird.

Zu mal du gar kein pChar brauchst. Denn Stream.Read/Write möchte einen Speicherbereich übergeben haben. Es genügt also vollkommen, wenn du als Buffer das erste Zeichen des Textes übergibst. Also Read/Write(models[i].Dateipfad[1], Len);


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Feb 27, 2011 15:50 
Offline
DGL Member

Registriert: Mi Jan 05, 2011 14:55
Beiträge: 47
Programmiersprache: Delphi, C++,C
Danke erstmal für den Tip.
Leider ist das nicht der Fall, da ich so schon lange Texte gespeichert hab. Die Probleme entstehen schon wiel früher, da aus irgend einem Grund die Länge des Array nicht auslesen kann, welche als erstes gespeichert wird. Wenn ich nur integer und string variablen hab klappt alles ohne Porbleme.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Feb 27, 2011 18:38 
Offline
DGL Member
Benutzeravatar

Registriert: Di Apr 29, 2008 18:56
Beiträge: 1213
Programmiersprache: Delphi/FPC
Hey,

nimm dir mal nen HexEditor (ich kann dir HxD empfehlen) un guck dir mal deine Datei an. Da müsste ja jetzt in den ersten 4 Byte die Anzahl an Models stehen. Vlt arbeitet die Laderoutine richtig un der Fehler tritt beim speichern auf?
Weiterhin empfehl ich dir für solche Konstrukte eine extra Klasse anzulegen (TModel oder so) die kannst du dann ganz easy mit einer TObjectList in deiner TModelList verwalten. Da wird das ganze auch etwas übersichtlicher, weil dann der Aufruf ungefähr so aussieht:

Code:
procedure TModelliste.SpeicherInListe;
var
  Stream: TFileStream;
  i: Integer;
begin
  Stream := TFileStream.Create(ExtractFilePath(Application.ExeName)+'\material\models.liste', fmCreate);
  try
    i := models.Count;
    Stream.Write(i, SizeOf(i));
    for i := 0 to models.Count-1 do
      TModel(models[i]).SaveToStream(Stream);
  finally
    Stream.Free;
  end;
end;


MfG Bergmann.

_________________
Aktuelle Projekte: BumpMapGenerator, Massive Universe Online
Auf meiner Homepage gibt auch noch paar Projekte und Infos von mir.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Feb 28, 2011 09:26 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Ich kann dir dennoch nur ans Herz legen nicht mit PChars zu arbeiten. Außerdem solltest du dir ein paar Hilfsfunktionen, wenn nicht sogar eine entsprechende Klasse dafür, schreiben. Also für alle Typen die du benutzt. Read/WriteInteger, Read/WriteSingle, Read/WriteString. Diese bekommen einen Stream und den Wert übergeben. Wenn du dann nur diese Methoden benutzt reduzierst du mögliche Fehlerquellen, da wirklich immer auf die gleiche Art und Weise gelesen und geschrieben wird. Außerdem ersparrt es dir bei Strings massiv die Arbeit. Wenn du etwas umstellen möchtest, dann genügt es eine Methode anzupassen und alles arbeitet anders.

Zu deinem Problem. Da es ja scheinbar nicht ganz so einfach ist. Du solltest dich durch den Code debuggen. Überprüfe was weggeschrieben wird. Eventuell sogar wie viele Daten weggeschrieben wurden. Mit einem HexEditor solltest du dir dann auch das Resultat anschauen und Überprüfen ob die dort enthaltenen dem entsprechen was du erwartest. Also 4 Byte Größe am Anfang. Dann 6x 4 Byte (Singles), dann 4Byte Stringgröße und anschließend der String. Was für ein Delphi hast du? Neuere Delphis benutzen per Default WideStrings. Und beim Einlesen dann auch entsprechend debuggen und genau schauen welcher Wert wo augelesen wird und wo eventuell der Fehler passiert.

Wobei ich bei Einstellungen etc. heutzutage auch keine Streams mehr benutzen würde. Für so einen Fall drängen sich XML Dateien förmlich auf. Es würde als Text in Baumstruktur gespeichert werden. Das Einlesen dauert zwar einen Bruchteil länger dafür hat man aber nicht diese Probleme, dass alles bis aufs kleinste Byte stimmen muss. Zur Überprüfung oder Ändern der Struktur könnte man da dann aber auch einen Texteditor benutzen. Je nachdem was man benutzt bedeutet es aber auch etwas mehraufwand beim Programmieren als bei Streams. Aber wenn man sich Hilfskonstrukte macht, dann braucht man das nicht immer und immer wieder machen zu müssen.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Feb 28, 2011 10:55 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Sep 23, 2002 19:27
Beiträge: 5812
Programmiersprache: C++
Ich werf mal die Helferklassen TWriter und TReader in dem Raum (classes.pas), die zwar eigentlich nur zur internen Delphinutzung gedacht sind, sich aber prima für das Schreiben und Auslesen diverser Datentypen geeignet sind, bringen sie doch für fast alle Datentypen entsprechende Funktionen mit. Dass sieht dann im Code so aus :
Code:
var
 Writer : TWriter;
...
Writer := TWriter.Create(pStream, 128);
...
Writer.WriteInteger(Length(Mesh));
...
Writer.WriteString(GLBinaryModelTexturePool.TextureName[i]);
...

_________________
www.SaschaWillems.de | GitHub | Twitter | GPU Datenbanken (Vulkan, GL, GLES)


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Feb 28, 2011 12:05 
Offline
DGL Member

Registriert: Mi Jan 05, 2011 14:55
Beiträge: 47
Programmiersprache: Delphi, C++,C
Danke für die Antworten.
@ Bergmann diese Vermutung habe ich auch. Ich werd mir das mal mit nem hex-editor anschauen.
@sascha Danke für den Tipp. Werd ich mir auch mal zu Hause anschsuen

Danke noch mal für die Hilfe

Edit : OK wie befürchtet wird die Größe nicht richtig geschrieben. Werd jetzt mal mit Writer und Reader testen.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Feb 28, 2011 19:47 
Offline
DGL Member

Registriert: Mi Jan 05, 2011 14:55
Beiträge: 47
Programmiersprache: Delphi, C++,C
Danke an alle.
Sascha's Tipp hat gut funktioniert.


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 8 Beiträge ] 
Foren-Übersicht » Programmierung » Allgemein


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 4 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.009s | 14 Queries | GZIP : On ]