Entwickler-Ecke

Dateizugriff - Speichern / laden einer Dynamischen Array (TMemoryStream)


Niko S. - Mi 28.10.09 19:46
Titel: Speichern / laden einer Dynamischen Array (TMemoryStream)
Hallöchen,

Ich wollte eine doppelte dynamische Array speichern.
In der Datei sollte zuerst der Kopf geschrieben werden der "fest" ist und danach die Array.
Die Array ist so definiert:

Delphi-Quelltext
1:
Map: array of array of TMap;                    


und die Speicher / Laderoutinen sind folgende:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
procedure TForm3.LoadMap(Datei: String);
var
  MapfileIn: TMemoryStream;
  MapFileOut: TMemoryStream;
  i: integer;
begin
  Application.OnIdle := nil;
  try
    MapFileIn := TMemoryStream.Create;
    MapFileOut := TMemoryStream.Create;
    MapFileIn.LoadFromFile(Datei);
    DecompressStream(MapFileIn,MapFileOut);
    MapFileOut.read(MapHeader, SizeOf(MapHeader));
    setlength(map,MapHeader.Size);
    for i := 0 to MapHeader.Size-1 do
    begin
      setlength(map[i],MapHeader.Size);
    end;
    MapFileOut.Read(Map,SizeOf(Map));
  finally
    FreeAndNil(MapFileIn);
    FreeAndNil(MapFileOut);
  end;
  Application.OnIdle := idle;
end;

procedure TForm3.SaveMap(Datei: String);
var
  MapfileIn: TMemoryStream;
  MapFileOut: TMemoryStream;
begin
  try
    MapFileIn := TMemoryStream.Create;
    MapFileOut := TMemoryStream.Create;
    MapFileIn.Write(MapHeader, SizeOf(MapHeader));
    MapFileIn.Write(Map, SizeOf(Map));
    CompressStream(MapFileIn, MapFileOut);
    MapFileOut.SaveToFile(Datei);
  finally
    FreeAndNil(MapFileIn);
    FreeAndNil(MapFileOut);
  end;
end;


Nun gibt es ein Problem, ich kann NACH dem laden nicht mehr auf die Array zugreifen.
Egal welche stelle ich anfrage ich bekomme immer bei Map[x,y].. eine Access Violation.
Weiß vielleicht jemand was da falsch sein könnte? Bin neuling auf dem Gebiet dyn. Array & Dateispeicherung via Streams.

Edit: Ich weiß wo der fehler liet, das funktioniert ja nur für eine statische array so wie das jetzt ist..
Ich werd mal schauen wie man das anders lösen könnte.

Für die die es interessiert, ich habe das so gelöst:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
procedure TForm3.LoadMap(Datei: String);
var
  MapfileIn: TMemoryStream;
  MapFileOut: TMemoryStream;
  i,q: integer;
begin
  Application.OnIdle := nil;
  try
    MapFileIn := TMemoryStream.Create;
    MapFileOut := TMemoryStream.Create;
    MapFileIn.LoadFromFile(Datei);
    DecompressStream(MapFileIn,MapFileOut);
    MapFileOut.read(MapHeader, SizeOf(MapHeader));
    setlength(map,MapHeader.Size);
    for i := 0 to MapHeader.Size-1 do
    begin
      setlength(map[i],MapHeader.Size);
      for q := 0 to MapHeader.Size-1 do
      begin
        MapFileOut.Read(Map[i,q],SizeOf(Map[i,q]));
      end;
    end;
  finally
    FreeAndNil(MapFileIn);
    FreeAndNil(MapFileOut);
  end;
  Application.OnIdle := idle;
end;

procedure TForm3.SaveMap(Datei: String);
var
  MapfileIn: TMemoryStream;
  MapFileOut: TMemoryStream;
  i,q: integer;
begin
  try
    MapFileIn := TMemoryStream.Create;
    MapFileOut := TMemoryStream.Create;
    MapFileIn.Write(MapHeader, SizeOf(MapHeader));
    for I := 0 to MapHeader.Size-1 do
      for Q := 0 to MapHeader.Size-1 do
        MapFileIn.Write(Map[i,q], SizeOf(Map[i,q]));
    CompressStream(MapFileIn, MapFileOut);
    MapFileOut.SaveToFile(Datei);
  finally
    FreeAndNil(MapFileIn);
    FreeAndNil(MapFileOut);
  end;
end;

Keine Ahnung obs elegant ist oder nicht, allerdings funktioniert das bei akzeptabler Geschwindigkeit.
Speichern ~0,2 sekunden
Laden ~0,08 sekunden
Wobei die dynamischen größen im moment 256 betragen also ist Map: array[0..255] of array[0..255] of TMap;
Ich schätze mal dass sich die Zeiten drastisch reduzieren werden sobald die Array kleiner ist..
bei 128 müsste das ganze 4 mal schneller sein.. und bei 64 wäre das dann 16 mal schneller ^^


Xion - Mo 02.11.09 22:28

Du kannst als Denkanstoß das mal so probieren (so mach ichs immer)


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
procedure Save;
var Txt: TextFile;
    Line: String;
begin
  AssignFile(Txt,FILENAME);
  ReWrite(Txt);
  
  Line:='';
  for X:= 0 to High(Map) do
    begin    
      for Y:= 0 to High(Map[X]) do
        Line:=Line+'|'+Map[X,Y];

      WriteLn(Txt,Line);
    end;

  CloseFile(Txt);
end;


Laden analog mit ReSet(Txt);

Ist enorm schnell hatte ich immer das Gefühl.


Horst_H - Mo 02.11.09 23:52

Hallo,

ich nehme mal an Simak, hat seine Datei komprimiert ;-)
Das ist mit Textdateien eher nachträglich möglich.
Aber ich gehe davon aus das wenigstens TMap eine konstante Größe hat.
Dadurch kann man das zweidimensionale Feld auch zeilenweise wegschreiben.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
  MapFileIn := TMemoryStream.Create;
  MapFileOut := TMemoryStream.Create;
  MapFileIn.LoadFromFile(Datei);
  DecompressStream(MapFileIn,MapFileOut);
  MapFileOut.read(MapHeader, SizeOf(MapHeader));
  with MapHeader do
    begin
    setlength(map,Size);
    for i := 0 to Size-1 do
      begin
      setlength(map[i],Size);
      //Jetzt in einem Rutsch von 0..Size-1 TMap Elemente einlesen
      MapFileOut.Read(Map[i,0],SizeOf(TMap)*Size);
      end;


Gruß Horst