2D Array als Datei speichern

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Littellittel
Beiträge: 20
Registriert: Mi 22. Apr 2015, 16:25

2D Array als Datei speichern

Beitrag von Littellittel »

Hallo,
Ich möchte in einem Programm ein statisches 2D Array abspeichern und es später wieder auslesen können. Ich habe es mit einem Stream versucht.
zum speichern:

Code: Alles auswählen

procedure TEditor.btnsaveClick(Sender: TObject);
var
  Fstream: TFileStream;
  i,j:Integer;
begin
 if SaveDialog1.Execute then
 begin
  Fstream := TFileStream.Create(SaveDialog1.FileName, fmCreate);
  try
    for i := 1 to 480 do
    begin for j := 1 to 320 do
          begin
             Fstream.Write(Feld[i,j].Groundtyp,SizeOf(Feld));
          end;
    end;
  finally
    Fstream.Free;
  end;
  ShowMessage('saved!');
 end;
end; 
und zum öffnen:

Code: Alles auswählen

procedure TEditor.btnOpenClick(Sender: TObject);
var
  Fstream: TFileStream;
  i,j:Integer;
begin
  if OpenDialog1.Execute then
  begin
   Fstream := TFileStream.Create(OpenDialog1.FileName , fmOpenRead);
   try
     for i := 1 to 480 do
     begin for j := 1 to 320 do
           begin
             FStream.Read(Feld[i,j].Groundtyp, SizeOf(Feld));
             Feld[i,j].AEnderung:=true;
           end;
     end;
   finally
     FStream.Free;
   end;
  end;
  draw;
end;   
Es tut seinen Job, allerdings wird die Datei über 5gb groß und es zu speichern und öffnen dauert dementsprechend lange.
Gibt es eine Möglichkeit das Array anders/effektiver zu speichern?

Danke im Voraus

Benutzeravatar
theo
Beiträge: 10872
Registriert: Mo 11. Sep 2006, 19:01

Re: 2D Array als Datei speichern

Beitrag von theo »

Was ist "Feld" und warum reservierst du Platz für das ganze "Feld" (SizeOf(Feld)) wenn du nur Groundtyp speicherst?

Littellittel
Beiträge: 20
Registriert: Mi 22. Apr 2015, 16:25

Re: 2D Array als Datei speichern

Beitrag von Littellittel »

Feld ist das Array.
Ich habe versucht nur Platz für "Feld.Groundtyp" zu reservieren allerdings meckert er dann das ich zu wenig Parameter habe selbes Problem mit "Feld[].Groundtyp"

Benutzeravatar
theo
Beiträge: 10872
Registriert: Mo 11. Sep 2006, 19:01

Re: 2D Array als Datei speichern

Beitrag von theo »

Aber du musst ja wissen, was Feld.Groundtyp ist.
Dann mach doch einfach SizeOf(Boolean) oder SizeOf(Integer) oder was es halt ist.

Littellittel
Beiträge: 20
Registriert: Mi 22. Apr 2015, 16:25

Re: 2D Array als Datei speichern

Beitrag von Littellittel »

Danke für die Antwort,
aber das funktioniert nicht. Wenn ich Sizeof (Groundtyp)( Groundtyp ist der integer im record) sagt er den identifier nicht findet

Benutzeravatar
theo
Beiträge: 10872
Registriert: Mo 11. Sep 2006, 19:01

Re: 2D Array als Datei speichern

Beitrag von theo »

Das habe ich auch nicht gesagt.
Ich sagte SizeOf(Integer)

Mathias
Beiträge: 6918
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: 2D Array als Datei speichern

Beitrag von Mathias »

Code: Alles auswählen

  Fstream.Write(Feld[i,j].Groundtyp,SizeOf(Feld[i,j].Groundtyp));

Zeig doch einfach mal die Deklaration von Feld und Groundtyp.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Littellittel
Beiträge: 20
Registriert: Mi 22. Apr 2015, 16:25

Re: 2D Array als Datei speichern

Beitrag von Littellittel »

ok,
das funktioniert ich dachte das Integer währe nur ein Platzahlter für den Namen des Integers :D .

Die Deklaration ist folgende:

Code: Alles auswählen

  TWelt=record
    AEnderung:boolean;
    Groundtyp:Integer;
    Spieler:integer;
  end;
Feld: Array [0..481,0..321] of TWelt;
 

Komoluna
Beiträge: 565
Registriert: So 26. Aug 2012, 09:03
OS, Lazarus, FPC: Windows(10), Linux(Arch)
CPU-Target: 64Bit

Re: 2D Array als Datei speichern

Beitrag von Komoluna »

In deinem ursprünglichem Code hast du für jede Zelle deines Feldes das gesamte Feld abgespeichert. Somit liegt der Speicherverbrauch bei

Code: Alles auswählen

Feldgröße ^ 2
Der Write Prozedur übergibst du nur eine Position im Arbeitsspeicher(Pointer) und die Größe deines Datentyps(wieviele Bits kopiert werden sollen).
Wenn du also die gesamte Größe deines Feldes im Speicher so oft, wie du Zellen im Feld hast abspeicherst, wird die Datei natürlich sehr groß.

Guck dir das hier mal an:
http://www.delphi-treff.de/tutorials/da ... g/streams/

MFG

Komoluna
Programmer: A device to convert coffee into software.

Rekursion: siehe Rekursion.

Littellittel
Beiträge: 20
Registriert: Mi 22. Apr 2015, 16:25

Re: 2D Array als Datei speichern

Beitrag von Littellittel »

Danke für alle antworten,
Die Lösung mit dem Sizeof(integer) hat aber schon alle Probleme gelöst.

Warf
Beiträge: 2120
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: 2D Array als Datei speichern

Beitrag von Warf »

Ich würde da anders ran gehen, 2 Statische Arrays, einen für die Informationen die Abgespeichert werden (Groundtyp) und einen für andere Informationen (AEnderung) und dann einfach:

Code: Alles auswählen

type
  TGroundMap = Array[1..480] of Array[1..320] of Integer;
  TChangeMap = Array[1..480] of Array[1..320] of Boolean;
 
...
// Load
  FStream.Read(MyGroundMap, SizeOf(MyGroundMap);
  FillByte(MyChangeMap, SizeOF(MyChangeMap), $00); // AEnderung := False
// Save
  FStream.Write(MyGroundMap, SizeOf(MyGroundMap);
  FillByte(MyChangeMap, SizeOF(MyChangeMap), $00);
Performanter, Kürzer und weniger Speicheraufwendig (Da die Variablen für die Forschleifen nicht benötigt werden)

Littellittel
Beiträge: 20
Registriert: Mi 22. Apr 2015, 16:25

Re: 2D Array als Datei speichern

Beitrag von Littellittel »

Ich glaube nicht das das so sinnvoll wäre denn Aenderung muss nicht abgespeichert werden es wird nur zu jedem Punkt im Array gegeben damit die draw Funktion das ganze Array ins Image malt.

Warf
Beiträge: 2120
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: 2D Array als Datei speichern

Beitrag von Warf »

Littellittel hat geschrieben:Ich glaube nicht das das so sinnvoll wäre denn Aenderung muss nicht abgespeichert werden es wird nur zu jedem Punkt im Array gegeben damit die draw Funktion das ganze Array ins Image malt.
Desshalb 2 Arrays, einer enthält die zu speichernden Informationen (TGroundMap) und einer die Zusätzlichen informationen (TChangeMap) und

Code: Alles auswählen

  FillByte(MyChangeMap, SizeOF(MyChangeMap), $00);
macht nichts anderes als den Gesammten Array von änderungen mit False zu überschreiben.
Der zugriff auf die Daten wäre dann

Code: Alles auswählen

MyGroundMap[x, y] := 15; // Äquivalent zu deinem Feld[x, y].Groundtyp := 15;
MyChangeMap[x, y] := True;  // Äquivalent zu deinem Feld[x, y].AEnderung:= True;
Du hättest zwar einen Array mehr, könntest aber durch Memory Operationen weitaus schneller und Einfacher die Daten bearbeiten, Modellieren und in Stream Schreiben und auslesen

Am schönsten wäre Natürlich wenn du dir noch eine Klasse drumherum Basteln würdest, damit könntest du 2(oder Mehr) Informationsquellen (arrays) verwalten als ein Objekt

BSP:

Code: Alles auswählen

TMapData = class
private
  FGroundTyp: TGroundMap;
  FAenderung: TChangeMap;
  ...
public
  property Aenderung[x, y: Integer]: Boolean read GetAenderung; // Readonly da du Änderungen ja klassenintern detektieren kannst
  property GroundTyp[x, y: Integer]: Integer read GetGroundTyp write SetGroundTyp; default;
  ...
  procedure SaveMap(Filename: String);
  procedure LoadMap(Filename: String);
  ...
end;

Littellittel
Beiträge: 20
Registriert: Mi 22. Apr 2015, 16:25

Re: 2D Array als Datei speichern

Beitrag von Littellittel »

OK,
ich weiß was du meinst aber was hat das denn genau für einen Vorteil gegenüber eines records?
Wird bei der Variante mit record etwa alles gespeichert (also auch AEnderung und Spieler)?

Warf
Beiträge: 2120
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: 2D Array als Datei speichern

Beitrag von Warf »

Durch 2 Statische Arrays hast du die beiden Informationen in Getrenten Speicherblöcken, und kannst einfach einen Via Memory Operationen bearbeiten, ohne Einfluss auf die Anderen Daten zu nehmen der Speicher sieht etwa so aus:

Code: Alles auswählen

 
|###########################|
|####GroundMap Array[0,0]####|
|####GroundMap Array[0,1]####|
|####GroundMap Array[1,0]####|
|####GroundMap Array[1,1]####|
|###########################|
|####ChangeMap Array[0,0]####|
|####ChangeMap Array[0,1]####|
|####ChangeMap Array[1,0]####|
|####ChangeMap Array[1,1]####|
|###########################|
Bei dem Record

Code: Alles auswählen

 
|#######################################|
|####RecordArray Array[0,0].GroundType####|
|####RecordArray Array[0,0].Aenderung####|
|####RecordArray Array[0,1].GroundType####|
|####RecordArray Array[0,1].Aenderung####|
|####RecordArray Array[1,0].GroundType####|
|####RecordArray Array[1,0].Aenderung####|
|####RecordArray Array[1,1].GroundType####|
|####RecordArray Array[1,1].Aenderung####|
|#######################################|
Nun kannst du einfach bei den 2 Arrays sagen z.B. Fillbyte(Array1, SizeOf(Array1), $00) damit wird jedes Feld des Arrays1 mit dem wert $00 überschrieben ohne dass du die Daten aus Array2 zu ändern, mit dem Record musst du mit for Schleifen arbeiten, und nur den einen wert überschreiben. Damit werden viele aktionen zu Einzeilern die sonst komplexe for blöcke sind, und es ist Performanter und der Speicheraufwand ist der selbe

Antworten