AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

TFileStream mit dynamischen Array

Ein Thema von Fischli80 · begonnen am 15. Sep 2004 · letzter Beitrag vom 20. Sep 2004
Antwort Antwort
Fischli80

Registriert seit: 4. Dez 2002
Ort: Dresden
25 Beiträge
 
Delphi 5 Professional
 
#1

TFileStream mit dynamischen Array

  Alt 15. Sep 2004, 23:08
Habe folgenden Sachverhalt:

Delphi-Quellcode:
type x = record

          x1 : string [255];
     x2 : string [40];
          x3 : string [80];
          x4 : string [50];
          x5 : string [4];
     x6 : byte;

    end;

     y = record

          y1 : string [255];
     y2 : string [80];
     y3 : string [40];
     y4 : string [20];
     y5 : byte;
     y6 : byte;
     y7 : byte;
     y8 : byte;


    end;

     z = record
   
     z1 : x;
     z2 : array of y;

    end;

var myZ : z;

procedure saveZToFile;

var zf : TFileStream;

begin

  fz := TFileStream.Create ('test.dat', fmCreate);
  fz.WriteBuffer (myZ, SizeOf(myZ));
  fz.free;

end;


procedure loadZFromFile;

var zf : TFileStream;
 
begin

  fz := TFileStream.Create ('test.dat', fmOpenRead);
  fz.ReadBuffer (myZ, SizeOf(myZ));
  fz.free;

end;

Mein Problem ist nun, dass der aktuelle Datensatz nicht richtig gespeichert wird, wobei
anscheinend die SizeOf Methode nicht die richtige Größe ermittelt. Durch testen ist mir
aufgefallen, dass es damit zusammenhängt, dass das Array dynamisch ist bzw. wenn Strings
nicht in der Länge terminiert sind.

Aber zur Laufzeit ist myZ genau bestimmt und das Array mittels SetLength auch begrenzt auf
wenige Datensätze.

Wie kann ich nun dieses Konstrukt speichern und laden???
Was hab ich missverstanden? Die entstehende Datei beim speichern ist 440 Byte groß also
ca die Größe von x.

Hoffe Ihr könnt mir helfen
Die Welt ist rund...also lasst uns von hinten angreifen
  Mit Zitat antworten Zitat
Thebe

Registriert seit: 25. Jul 2004
Ort: Wedel
78 Beiträge
 
Delphi 6 Enterprise
 
#2

Re: TFileStream mit dynamischen Array

  Alt 15. Sep 2004, 23:27
Du musst statt record oben packed record benutzen.
  Mit Zitat antworten Zitat
Benutzerbild von Manzoni
Manzoni

Registriert seit: 15. Feb 2004
Ort: Berlin
120 Beiträge
 
Delphi 7 Enterprise
 
#3

Re: TFileStream mit dynamischen Array

  Alt 15. Sep 2004, 23:58
sicher? hab zwar keine Ahnung wo sein Problem ist, aber packed bezieht sich doch nur auf eine Komprimierung im Speicher, oder ?
Bob
  Mit Zitat antworten Zitat
Benutzerbild von dizzy
dizzy

Registriert seit: 26. Nov 2003
Ort: Lünen
1.932 Beiträge
 
Delphi 7 Enterprise
 
#4

Re: TFileStream mit dynamischen Array

  Alt 16. Sep 2004, 01:24
Keine Kompression, sondern die eingestellte Ausrichtung wird übergangen, und jedes Element beginnt mit packed direkt nachdem das vorige endet. Ohne packed werden die Elemente an 8 Byte (Standardeinstellung - kann geändert werden) ausgerichtet, so das ein Element nicht z.B. am 4. Byte der Struktur beginnen kann, sondern immer nur in 8 Byte-Schritten.
Das ist/war eine Geschwindigkeitsfrage, und auch zur Kompatibilität zu anderen Sprachen/Settings. Mal abgesehen vom x86 haben viele CPUs sonst auch Probleme mit nicht ausgerichteten Feldern - so wohl auch der Athlon64. Den kann man damit richtig schön ärgern und langsam machen . x86er korrigieren das intern. (afaik!)

Zum Schreiben ist packed hingegen sehr praktisch, da ein Datentyp der nicht genau an einer Grenze aufhört so nicht mit Nullen aufgefüllt werden muss (Padding), und dann im File doch etwas "schöner" aussieht .

gruss,
dizzy
Fabian K.
INSERT INTO HandVonFreundin SELECT * FROM Himmel
  Mit Zitat antworten Zitat
Chewie

Registriert seit: 10. Jun 2002
Ort: Deidesheim
2.886 Beiträge
 
Turbo Delphi für Win32
 
#5

Re: TFileStream mit dynamischen Array

  Alt 16. Sep 2004, 09:51
Mal langsam hier, Leute. Erstens richtet packed in der Standardeinstellung an 4 Byte- und nicht an 8 Byte-Grenzen aus und zweitens hat das hier mit dem Problem nichts zu tun.
Das Problem ist vielmehr, dass dynamische Array- und lange String-Variablen (auch Recordfelder) Zeiger auf den dafür allokierten Heap-Speicher sind, das Array bzw. der String ist also nicht direkt im Record enthalten. Um den Record dann sebst in der Datei zu speichern, muss man die Zeiger dann selbst dereferenzieren. Eine Möglichkeit wäre z.B, das so zu machen:

Delphi-Quellcode:
type
  TMyRec = record
    Data1: Integer;
    Count: Integer;
    Vals: Array of Integer;
  end;
var
  fs: TFileStream;
  rec: TMyRec;
begin
  fs := TFileStream.Create({wie gehabt});
  rec.Count := Length(rec.Vals);
  fs.WriteBlock(rec, Sizeof(Rec) - Sizeof(Pointer));
  fs.WriteBlock(rec.Vals^, Length(Vals) * Sizeof(Integer));
  fs.Free;
end;
Martin Leim
Egal wie dumm man selbst ist, es gibt immer andere, die noch dümmer sind
  Mit Zitat antworten Zitat
Benutzerbild von dizzy
dizzy

Registriert seit: 26. Nov 2003
Ort: Lünen
1.932 Beiträge
 
Delphi 7 Enterprise
 
#6

Re: TFileStream mit dynamischen Array

  Alt 16. Sep 2004, 11:58
Zitat von Chewie:
richtet packed in der Standardeinstellung an 4 Byte- und nicht an 8 Byte-Grenzen aus
Dann hab ich wohl mal gefummelt, ohne zurück zu fummeln...

Zitat von Chewie:
und zweitens hat das hier mit dem Problem nichts zu tun.
Mit den Pointern hast du völlig Recht. Das hab ich da mal spontan übersehen, und das wird hier wohl das Hauptproblem sein. Allerdings ist es trotzdem eine gute Idee packed zu benutzen, da hier auch einige Byte-Werte vorkommen, die dann nicht auf 4 Bytes gepaddet werden müssten, und beim Write nach jedem Byte 3 Byte nullen nach sich zögen.

mfg, dizzy
Fabian K.
INSERT INTO HandVonFreundin SELECT * FROM Himmel
  Mit Zitat antworten Zitat
Fischli80

Registriert seit: 4. Dez 2002
Ort: Dresden
25 Beiträge
 
Delphi 5 Professional
 
#7

Re: TFileStream mit dynamischen Array

  Alt 16. Sep 2004, 14:08
@Chewie

Erklärung scheint mir allgemein sehr plausibel.
Aber könntest du zu meinem besseren Verständnis noch ein paar Worte verlieren zu dem was
dein Quellcode versucht mir zu sagen?

rec.Count gibt also die tatsächliche Länge des Arrays an oder? Bei mir ist das auch wieder
ein Record. Macht das nen Unterschied?

Und wenn ich deinen Programmablauf umkehren möchte, sozusagen wieder laden, wie muss dass dann aussehen, damit wieder ein vernünftiger Record bei rauskommt?

Bin wahrscheinlich zu verwirrt um die Tomaten von den Augen zu bekommen

Und gibt es nicht eine Variante ein dynamisches Array zur Laufzeit fixieren zu lassen, quasi eine Möglichkeit es in ein statisches zu verwandeln?
Die Welt ist rund...also lasst uns von hinten angreifen
  Mit Zitat antworten Zitat
Chewie

Registriert seit: 10. Jun 2002
Ort: Deidesheim
2.886 Beiträge
 
Turbo Delphi für Win32
 
#8

Re: TFileStream mit dynamischen Array

  Alt 16. Sep 2004, 15:02
rec.Count gibt die Länge des Arrays an, ist also vor dem Schreiben identisch mit Length(Array). Ich benutz das nur, damit ich später beim Einlesen die Länge des Arrays weiß, denn die brauch ich ja. Den Code fürs Einlesen schreib ich dir jetzt, hatte vorhin keine Zeit mehr.

Delphi-Quellcode:
type
  TMyRec = record
    Data1: Integer;
    Count: Integer;
    Vals: Array of Integer;
  end;
var
  fs: TFileStream;
  rec: TMyRec;

begin
  fs := TFileStream.Create({wieauchimmer});
  fs.Read(rec, Sizeof(rec) - Sizeof(Pointer)); //wir lesen die ersten beiden Felder ein
  SetLength(rec.Vals, rec.Count); //wir setzen die Anzahl der Elemente auf den
                                   //Wert, den wir eben eingelesen haben
  fs.Read(rec.Vals^, rec.Count * Sizeof(Integer)); //nun lesen wir den Inhalt des Arrays ein
  fs.Free;
end;
Wenn du nun einen Array of Record benutzt, musst du beim Lesen und schreiben halt die Länge des Arrays mit Sizeof(RecordTyp) multiplizieren.
Soweit verständlich?

Ach ja, eine Variante, ein dynamisches Arrays so in ein statisches umzuwandeln, kenn ich leider nicht.
Martin Leim
Egal wie dumm man selbst ist, es gibt immer andere, die noch dümmer sind
  Mit Zitat antworten Zitat
Fischli80

Registriert seit: 4. Dez 2002
Ort: Dresden
25 Beiträge
 
Delphi 5 Professional
 
#9

Re: TFileStream mit dynamischen Array

  Alt 20. Sep 2004, 13:34
Erstmal Danke für die Hilfe bisher. Ich glaub ich habs bald.
Aber so ganz klappts noch ni bei mir. Hier mal mein Quellcode:


** Typdefinitionen **


Delphi-Quellcode:
type
     currListData = record

        s1 : string [255];
        s2 : string [80];
        s3 : string [40];
        s4 : string [50];
        s5 : string [4];
        b1 : byte;

     end;

     currListEntry = record

        s1 : string [80];
        s2 : string [40];
        s3 : string [20];
        s4 : string [255];
        b1 : byte;
        b2 : byte;
        b3 : byte;
        b4 : byte;

     end;

     currList = record

        data : currListData;
        count : integer;
        entries : array of currListEntry;

     end;
und nun meine 2 Funktionen:

Delphi-Quellcode:
function loadCurrList (fn : string; var cl:currList):boolean;
var f : TFileStream;
begin

  loadCurrList := true;

  try

    f := TFileStream.Create (fn, 0);
    f.Read(cl, Sizeof(cl) - Sizeof(Pointer));
      SetLength(cl.entries, cl.Count);
    f.Read(cl.entries^, cl.Count * Sizeof(currListEntry));
    f.free;

  except

    loadCurrList := false;

  end;

end;


function saveCurrList (fn : string; cl : currList):boolean;
var f : TFileStream;
begin

  saveCurrList := true;

  try


    f := TFileStream.Create(fn, fmCreate);
    cl.Count := Length(cl.entries);
    f.WriteBuffer(cl, Sizeof(cl) - Sizeof(Pointer));
    f.WriteBuffer(cl.entries^, Length(entries) * Sizeof(CurrListEntry));
    f.Free;

  except

    saveCurrList := false;

  end;

end;
Der Compiler liefert bei mir folgende Fehler bezüglich der Zeilen f.Read(c.entries^.... und f.WriteBuffer(cl.entries^.....

Zitat:
Fehler: Zeigertyp erwartet
Fehler: Inkompatible Typen
Fehler: Operator auf diesem Operandentyp nicht anwendbar
Ausserdem mußte ich den Befehl WriteBuffer nehmen, da bei WriteBlock die Antwort kam dies sei eine unbekannte Funktionen.

Hab ich was missverstanden?
Die Welt ist rund...also lasst uns von hinten angreifen
  Mit Zitat antworten Zitat
Chewie

Registriert seit: 10. Jun 2002
Ort: Deidesheim
2.886 Beiträge
 
Turbo Delphi für Win32
 
#10

Re: TFileStream mit dynamischen Array

  Alt 20. Sep 2004, 13:50
Einmal hast du nur entries anstelle von cl.entries geschrieben. Und die beiden anderen Fehler rühren wohl daher, dass der Compiler es nicht schnallt, dass ein dyn. Array ein Zeiger ist. Versuch also noch den Cast auf Pointer:
f.WriteBuffer(Pointer(cl.entries)^, Length(cl.entries) * Sizeof(CurrListEntry)); Analog beim Lesen.
Martin Leim
Egal wie dumm man selbst ist, es gibt immer andere, die noch dümmer sind
  Mit Zitat antworten Zitat
Antwort Antwort


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 17:05 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