Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Dynamisches Array speichern und einlesen (https://www.delphipraxis.net/36590-dynamisches-array-speichern-und-einlesen.html)

Jelly 22. Dez 2004 10:56


Dynamisches Array speichern und einlesen
 
Ich muss ein dynamisches Array speichern, und natürlich auch wieder einlesen.

Bei einem Statischen Array klappt das Speichern mit diesem Code:
Delphi-Quellcode:
var
  A : array[0..99,0..99,0..99] of double ;
begin
     FS := TFileStream.Create(txtfilename.text,fmCreate);
     try
        FS.Write (A,sizeof(A)) ;
     finally
        FS.free ;
     end ;
end ;
Bei einem dynamischen Array versagt die Routine aber. Worauf muss ich da achten?

Robert_G 22. Dez 2004 11:37

Re: Dynamisches Array speichern und einlesen
 
Zitat:

Zitat von Jelly
Bei einem dynamischen Array versagt die Routine aber. Worauf muss ich da achten?

Sie versagt, weil SizeOf 4 ergibt (misst nur die Größe des Zeigers ;) )
Die Frage ist: Willst du überhaupt ein normales Array nehmen?
Wäre maximovs Template version der dpCollectiondpCollection nicht um ein Vielfaches besser? :gruebel:

Jelly 22. Dez 2004 12:57

Re: Dynamisches Array speichern und einlesen
 
Ich habs jetzt irgendwie so hingekriegt:
Delphi-Quellcode:
     FS := TFileStream.Create(txtfilename.text,fmCreate);
     try
        FS.Write(N,sizeof(N)) ;
        for x := 0 to N-1 do
        for y := 0 to N-1 do
           for z := 0 to N-1 do begin
              FS.Write(A[x,y,z],SizeOf(TRecord))
           end ;
     finally
        FS.free ;
     end ;
Das klappt soweit. Auslesen halt analog.

Die Sache mit der Collection wäre auch ne Möglichkeit, allerdings hab ich jetzt schon die ganzen Daten in Arrays vorliegen, und die Zeit fehlt mir das zu ändern.

Chewie 22. Dez 2004 13:24

Re: Dynamisches Array speichern und einlesen
 
Du musst deinen Code nur minimal abändern:

Code:
var
  A : array[0..99,0..99,0..99] of double ;
begin
     FS := TFileStream.Create(txtfilename.text,fmCreate);
     try
        FS.Write (A[b][0][/b], [b]length(A) * sizeof(A[0][/b]) ;
     finally
        FS.free ;
     end ;
end ;
Grund: dynamische Array-Variablen sind nur Zeiger auf das Array. TFileStream.Write verlangt aber keine Adresse, sondern ein Datum, und das lieferst du mit A[0]. Und die Größe des Arrays im Speicher ist die Anzahl der Elemente mal der Größe eines Elements.

MaWi3.2 2. Jan 2005 16:22

Re: Dynamisches Array speichern und einlesen
 
Also erstmal zu dem :
length(A) * sizeof(A[0]
bei einem 10 mal 10 array ergibt das 40 und keine hundert...
hab ich da was falsch verstanden??

Und kann mir das nochmal jemand erklären ich habe nämlich das gleiche Problem nur bei mir funktioniert das ganze ganz und gar nicht....
Wenn ich mein dyn. Array Speicher speichert er das nicht vollständig ab und das lesen klappt dann gar nicht.


Das wäre meine Procedure zum Laden:
Delphi-Quellcode:
procedure TForm1.LadenClick(Sender: TObject);
var FS : TFileStream;
    svMatrix : array of array of integer;
begin
if OpenDialog1.Execute then
begin
     FS := TFileStream.Create(OpenDialog1.FileName,fmOpenRead);
     try
        FS.Read (svMatrix[0], length(svMatrix) * sizeof(svMatrix[0]) ;
     finally
        FS.free ;
     end ;
end;
end;

und das zum Speichern....
Delphi-Quellcode:
procedure TForm1.SpeichernClick(Sender: TObject);
var FS : TFileStream;
    svMatrix : array of array of integer;
begin
if SaveDialog1.Execute then
begin
     FS := TFileStream.Create(SaveDialog1.FileName,fmCreate);
     try
        FS.Write (svMatrix[0], length(svMatrix) * sizeof(svMatrix[0]) ;
     finally
        FS.free ;
     end ;
end;
end;
Habe das mit ner einfachen for Schleife bei mir mit Werten belegt aber beim einlesen kommt nix.
Was mache ich falsch?

Chewie 2. Jan 2005 17:40

Re: Dynamisches Array speichern und einlesen
 
Dynamische Arrays sind erstmal Zeiger. Ein 10 mal 10 Array ist also eine Liste von 10 Zeigern auf andere Speicherbereche. Du hast keinen zusammengehörigen Speicherbereich, deshalb musst du alles auf eindimensionale Arrays zurückführen und die einzeln abspeichern.

MaWi3.2 2. Jan 2005 19:00

Re: Dynamisches Array speichern und einlesen
 
Und warum funktioniert dann der mein Code nicht?

Chewie 3. Jan 2005 10:32

Re: Dynamisches Array speichern und einlesen
 
Zitat:

Zitat von MaWi3.2
Und warum funktioniert dann der mein Code nicht?

Dein Code funktioniert schon, nur macht er nicht das was du willst: Er speichert nämlich einfach die Adressen der Speicherbereiche, die deine Integer-Zahlen enthalten.

mytar 3. Jan 2005 10:48

Re: Dynamisches Array speichern und einlesen
 
Dass muss aber irgendwie so funktionieren,
dass man dass ganze mit einem Befehl in den Stream schreibt!

Denn bei Strings funktioniert das ja auch,
und da ist auf Position 0 ja auch ein Zeiger.

:-D

Christian Seehase 3. Jan 2005 11:46

Re: Dynamisches Array speichern und einlesen
 
Moin mytar,

Zitat:

Zitat von mytar
...da ist auf Position 0 ja auch ein Zeiger.

nein, ist er nicht.
Eine Stringvariable (Huge Strings) enthält einen Zeiger auf das erste Zeichen des Strings in den vier Zeichen vor dem ersten Zeichen steht die Länge, und die davor liegen vier Byte enthalten einen Referenzzähler.

Würdest Du nur

Delphi-Quellcode:
fs.Write(StringVariable,...);
angeben, würdest Du den Wert des Pointers und die Bytes dahinter schreiben.
Erst

Delphi-Quellcode:
fs.Write(StringVariable[1],...);
schreibt den Inhalt des Strings.

mytar 3. Jan 2005 12:00

Re: Dynamisches Array speichern und einlesen
 
Ist hier die Länge 255 als zweiter Write-Parameter verpflichtend?

(Hab ich mal gehört)!

:-D

Christian Seehase 3. Jan 2005 12:23

Re: Dynamisches Array speichern und einlesen
 
Moin Francis,

nein, die Länge kannst Du nach Bedarf angeben.
Ein ShortString hat eine maximle Länge von 255 Zeichen und enthält an der Stelle [0] ein Längenbyte.

Jetzt aber bitte Back To Topic.

Chewie 3. Jan 2005 13:01

Re: Dynamisches Array speichern und einlesen
 
Zitat:

Zitat von mytar
Dass muss aber irgendwie so funktionieren,
dass man dass ganze mit einem Befehl in den Stream schreibt!

Denn bei Strings funktioniert das ja auch,
und da ist auf Position 0 ja auch ein Zeiger.

:-D

Strings sind ja auch eindimensioanle Arrays. Bei denen funktioniert das mit meiner Methode ja auch wunderbar. Warum das bei mehrdimensionalen nicht geht, hab ich weiter oben geschrieben.

Einen Vorschlag hätt ich allerdings: Benutz statische Arrays, schalte die Bereichsüberprüfung ab und verwalte den Speicher selbst. Dann kannst du ganz leicht streamen, da statische Arrays einen zusammenhängenden Speicherblock einnehmen.

MaWi3.2 3. Jan 2005 16:10

Re: Dynamisches Array speichern und einlesen
 
Wie jetzt?
Ich brauche aber dyn. Arrays.
Das heißt ich müßte die Werte des Arrays einzeln in ne Datei schreiben und wieder auslesen?
Das ist aber umständliche.
Geht das wenn ich es ohne Streams sondern mit Asign und writeln mache?

MaWi3.2

Chewie 3. Jan 2005 16:19

Re: Dynamisches Array speichern und einlesen
 
OK, dann halt mit Codebeispielen:

So deklarierst du dein Array:
Delphi-Quellcode:
a: Array[0..0] of Array[0..0] of Integer;
Mittels Delphi-Referenz durchsuchenGetMem reservierst du für dieses Array dann Speicher. Wenn du es vergrößern willst, reservierst du neuen Speicher in der entsprechenden Größe, verschiebst alle Daten in diesen Speicherbereich und gibts den alten via Delphi-Referenz durchsuchenFreeMem frei. Letztendlich hast du so die Speicherverwaltung eines dynamischen Arrays nachgebaut.

Aber: Wenn du ohnehin weißt, dass du ein Array eines Array hast (das ist nicht ganz ein zweidimensionales Array), dann kannst du dir den ganzen Stress sparen, indem du einfach mit einer for-Schleife jedes einzelne Unter-Array speicherst.
Ich will mal gnädig sein ;)

Delphi-Quellcode:
var
  a: Array of Array of Integer;
  fs: TFileStream;
  i: Integer;

//...
  for i := Low(a) to High(a) do
    fs.write(a[i][0], Length(a[i]) * SizeOf(Integer));

MaWi3.2 3. Jan 2005 17:15

Re: Dynamisches Array speichern und einlesen
 
Supi. Dank Dir jetzt hab auch ich es verstanden und es funktioniert auch.
Danke für Deine Mühe und Geduld.

maximov 4. Jan 2005 11:46

Re: Dynamisches Array speichern und einlesen
 
Zitat:

Zitat von Chewie
OK, dann halt mit Codebeispielen:

So deklarierst du dein Array:
Delphi-Quellcode:
a: Array[0..0] of Array[0..0] of Integer;
Mittels Delphi-Referenz durchsuchenGetMem reservierst du für dieses Array dann Speicher. Wenn du es vergrößern willst, reservierst du neuen Speicher in der entsprechenden Größe, verschiebst alle Daten in diesen Speicherbereich und gibts den alten via Delphi-Referenz durchsuchenFreeMem frei. Letztendlich hast du so die Speicherverwaltung eines dynamischen Arrays nachgebaut.
...

Das muss ich nochmal richtig stellen, da dieser trick sehr praktisch ist, aber leider so nicht funktionieren kann. Denn zur adressierung der daten, in mehr als einer dimension, wird auch die max-anzahl benötig, die hier leider immer statisch 1 ist - und somit kann die erste dimension nicht erweitert werden:

addr := y * maxAnzahlX + x wäre zB. eine zweidimensionale addresierung, die hier leider versagt, da der kompiler ja nicht wissen kann, das man hier ein dynamisches array faken will.

Aber mit einer dimension funktioniert dieser trick prima und kann in speziellen fällen sinnvoll sein!

Chewie 4. Jan 2005 11:59

Re: Dynamisches Array speichern und einlesen
 
Hm, maximov ich fürchte du hast Recht :?
Das hab ich nicht bedacht. Man müsste noch eine Möglichkeit finden, dem Programm zur Laufzeut die Größe einer Dimension mitzuteilen. Aber das wäre zuviel des Gefrickels ;)


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:31 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-2025 by Thomas Breitkreuz