Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - arrays speichern


klausiemausie - Sa 28.02.09 19:18
Titel: arrays speichern
Sorry wenn ich frage, aber ich bin auf der Suche nach einem Beispielcode für das Speichern von arrays mit dem Savedialog, so dass der User einen Ort und einen Namen aussuchen kann für die Datei. hab suche schon benutzt und auch bruder google, wie man das mit savetofile löst hab ich gefunden, aber einen code wie das mit dem dialog klappt leider nicht. vielleicht hat ja einer von euch einen Beispielcode parat.
danke klaus


Delete - Sa 28.02.09 19:29


Delphi-Quelltext
1:
2:
if SaveDialog.Execute then
  Speichern(SaveDialog.Filename);


klausiemausie - Sa 28.02.09 19:30

hm ok, und was ist das "Speichern" in zeile 2, die variable die ich speichern will?


Bergmann89 - Sa 28.02.09 19:35

HI,

speichern is ne Proezedur und die würd ich so machen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
procedure Speichern(FileName: Stringarrayarray of String);
var list: TStringList;
var i: Integer;
begin
  list := TStringList.Create;
  for i := 0 to High(arraydo
    List.add(array[i]);
  list.saveToFile(FileName);
  list.free;
end;



und so rufst du die dann auf:

Delphi-Quelltext
1:
2:
if SaveDialog1.Execute then
  Speichern(SaveDialog1.FileName, MyArray);


so sollte das funzen habs aber noch net getestet...

MfG Bergmann


Keldorn - Sa 28.02.09 19:37

Die procedure, die für das Speichern verantwortlich ist ;-).
Poste bitte mal dein array bzw. Record. Was hast du drin?
Gugg mal bei http://www.delphi-treff.de/tipps/object-pascal/ da findest du 2 Themen (dyn array abspeichern und records abspeichern) Beides geht nur, wenn Du im Array bzw Record nicht strings hast, sondern shortstrings (z.B. name:string[20]);

Ansonsten würde ich dir Streams empfehlen und alles einzeln speichern, hast du auf die Dauer und bei Änderungen mehr Freude dran.

Gruß Frank


klausiemausie - Sa 28.02.09 19:51

ich möchte 2 arrays speichern, einmal einen array wo nur zahlen von 0-2 drin stehen und einen wo auch grössere zahlen drin stehen, bis 10.000 oder so.


Keldorn - Sa 28.02.09 19:57

wenn beide zusammen in eine Datei sollen, dann gehts nicht mit den oben genannten, würde dir dann wirklich Streams empfehlen.

Prinzipiell gibt es da im Forum ein paar Beiträge, (z.B. http://www.delphi-forum.de/viewtopic.php?t=66937&highlight=streams) ist zwar für Objekte, das Proinzip für ein dyn Array ist aber das gleiche.

poste aber trotzdem mal deine array-definition


klausiemausie - Sa 28.02.09 20:12

Region: Array[1..35] of single;
Zugehoerigkeit: Array[1..35] of byte;


jaenicke - Sa 28.02.09 20:57

Hier ein kleines Beispiel dafür, du brauchst nur zwei Buttons, dann sollte das so klappen:

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:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
procedure TForm1.Button1Click(Sender: TObject);
var
  Region: array[1..35of Single;
  Zugehoerigkeit: array[1..35of Byte;
  TestFile: TFileStream;
  TestMemStream: TMemoryStream;
  i: Integer;
begin
  for i := Low(Region) to High(Region) do
  begin
    Region[i] := i;
    Zugehoerigkeit[i] := i;
  end;

  TestFile := TFileStream.Create(ExtractFilePath(ParamStr(0)) + 'test.txt', fmCreate);
  try
    TestMemStream := TMemoryStream.Create;
    try
      // Die Größe des MemoryStreams setzen
      TestMemStream.SetSize(Length(Region) * SizeOf(Single));
      // Den Speicherbereich des Arrays in den des Streams kopieren
      CopyMemory(TestMemStream.Memory, @Region[Low(Region)], Length(Region) * SizeOf(Single));
      // Die Position zum Lesen auf den Anfang setzen
      TestMemStream.Position := 0;
      // Und von dort aus den Inhalt in die Datei kopieren
      TestFile.CopyFrom(TestMemStream, TestMemStream.Size);

      TestMemStream.SetSize(Length(Zugehoerigkeit) * SizeOf(Byte));
      CopyMemory(TestMemStream.Memory, @Zugehoerigkeit[Low(Region)], Length(Zugehoerigkeit) * SizeOf(Byte));
      TestMemStream.Position := 0;
      TestFile.CopyFrom(TestMemStream, TestMemStream.Size);
    finally
      TestMemStream.Free;
    end;
  finally
    TestFile.Free;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  Region: array[1..35of Single;
  Zugehoerigkeit: array[1..35of Byte;
  TestFile: TFileStream;
  TestMemStream: TMemoryStream;
  i: Integer;
begin
  TestFile := TFileStream.Create(ExtractFilePath(ParamStr(0)) + 'test.txt', fmOpenRead);
  try
    TestMemStream := TMemoryStream.Create;
    try
      // Aus der Datei einen Block in der Größe des Arrays lesen
      TestMemStream.CopyFrom(TestFile, Length(Region) * SizeOf(Single));
      // Und den Speicherbereich kopieren
      CopyMemory(@Region[Low(Region)], TestMemStream.Memory, Length(Region) * SizeOf(Single));

      TestMemStream.Position := 0;
      TestMemStream.CopyFrom(TestFile, Length(Zugehoerigkeit) * SizeOf(Byte));
      CopyMemory(@Zugehoerigkeit[Low(Region)], TestMemStream.Memory, Length(Zugehoerigkeit) * SizeOf(Byte));
    finally
      TestMemStream.Free;
    end;
  finally
    TestFile.Free;
  end;

  for i := Low(Region) to High(Region) do
  begin
    ShowMessage(FloatToStr(Region[i]));
    ShowMessage(IntToStr(Zugehoerigkeit[i]));
  end;
end;


klausiemausie - Sa 28.02.09 21:13

mit dem 2. button lade ich das dann quasi wieder oder?


jaenicke - Sa 28.02.09 21:33

Ja, genau. Bei dynamischen Arrays müsstest du die Größe mit speichern.


klausiemausie - Sa 28.02.09 21:59

also ich hab das mal so ausprobiert, aber es funktioniert nicht. weil der soll ja inner showmessage den inhalt des jeweiligen arrays anzeigen im 2. button, aber der zeit immer nur 2 mal 1 , 2 mal die 2 , 2 mal die 3, also in jedem array nur i quasi, soll ja aber eig nich so sein oder?


Keldorn - Sa 28.02.09 22:21

also ein klein wenig solltest Du dich mit dem geposteten schon auseinandersetzen, nicht bloß abkopieren ;-)

Zitat:

for i := Low(Region) to High(Region) do
begin
Region[i] := i;
Zugehoerigkeit[i] := i;
end;

mußt du natürlich rausnehmen, das hat jaenicke nur zum testen reingeschrieben


klausiemausie - Sa 28.02.09 22:43

oh, total übersehen, ähm ja, ich habs mir natürlich durchgelesen, habs auch versucht zu verstehen, aber das ist ein anderes thema


klausiemausie - Sa 28.02.09 22:49

ja aber wenn da drin steht dass dann region[i]:=i is, dann wird ja der eig inhalt des arrays gar nich gespeichert....durch was muss ich das ersetzen?


Keldorn - Sa 28.02.09 22:53

das
Zitat:

Region: array[1..35] of Single;
Zugehoerigkeit: array[1..35] of Byte;

muß aus der buttonclick auch noch raus.


jaenicke - Sa 28.02.09 23:15

user profile iconklausiemausie hat folgendes geschrieben Zum zitierten Posting springen:
oh, total übersehen, ähm ja, ich habs mir natürlich durchgelesen, habs auch versucht zu verstehen, aber das ist ein anderes thema
Wenn du etwas nicht verstehst, dann frag doch nach. Das ist ja kein Problem, aber du musst eben sagen was genau du nicht verstehst. :wink:


klausiemausie - Sa 28.02.09 23:31

jetz hab ichs hinbekommen, funktioniert alles so wies geht, danke nochma


klausiemausie - Sa 28.02.09 23:42

eine frage hättich dann aber noch: wie bekomme ich es hin, dass der user den namen der Datei aussuchen kann, und dann beim laden die auch wieder auswählen kann?


jaenicke - Sa 28.02.09 23:43

Ich hoffe du hast den Quelltext auch verstanden, so dass du sowas dann auch selbst benutzen kannst, wenn du etwas ähnliches wieder brauchst. ;-)

Für das Auswählen der Datei gibt die Komponente TSaveDialog unter Dialogs.

// EDIT:
Aber Moment mal, das stand doch als erste Antwort oben schon da. :lol: ;-)


klausiemausie - So 01.03.09 00:01

jo dein beispiel hab ich an sich verstanden, nur mit dem savetodialog komm ich nich klar, so wie das oben als beispiel stand, hat es nicht gefunzt


jaenicke - So 01.03.09 00:10

Naja, du musst Execute aufrufen, wenn das erfolgreich war, dann musst du speichern. Wohin steht dann in FileName. Wie das dann genau aussieht, kommt dann auf deinen Code an.
Dass da eine Methode "Speichern" stand, war ja nur ein Beispiel dafür, dass du an der Stelle etwas mit dem erhaltenen Dateinamen machen musst.


Delete - So 01.03.09 00:22

So isses. Ohne die Daten zu kennen hätte ich ja nicht Konkretes dahin schreiben können. Also muss man nur eine Methode "Speichern" schreiben, die den Dateinamen übernimmt und alles ist in Butter.


klausiemausie - So 01.03.09 10:40

ihr sprecht in rätseln...


Delete - So 01.03.09 11:30

Wieso? Du wolltest wissen, wie Du per Dialog einen Dateinamen auswählen kannst, um in diese Datei zu speichern. Das hab ich Dir in der ersten Antwort verraten. Da ich aber Deine Daten nicht kannte, habe ich die auszuführende Speichermethode halt "Speichern" genannt. Diese musst Du nur noch schreiben, dann kannst Du den Code aus meiner Antwort 1:1 übernehmen.


klausiemausie - So 01.03.09 12:11

hm und für die prozedur speichern, kann ich da den code von jaenicke nehmen?


klausiemausie - So 01.03.09 12:23

was mir noch eingefallen ist, ich könnte ja einfach den namen der zu speichernden datei in ne stringvariable einlesen, kann ich die variabable in den code mit einfügen, dass er in ne variable datei schreibt? also hier in dieser zeile
TestFile := TFileStream.Create(ExtractFilePath(ParamStr(0)) + 'test.txt', fmOpenRead);


Delete - So 01.03.09 12:39

Natürlich, sonst macht der Dialog ja keinen Sinn.

Delphi-Quelltext
1:
2:
TestFile := TFileStream.Create(OpenDialog.Filename, fmOpenRead); //zum Lesen
TestFile := TFileStream.Create(SaveDialog.Filename, fmOpenWrite); //zum Schreiben


klausiemausie - So 01.03.09 13:32

gut hab ich so geändert, kommt aber jetz ne fehlermeldung "Cannot open file", wenn ich auf den button zum speichern klicke


Delete - So 01.03.09 13:34

Zeig mal den Code zum Speichern.


klausiemausie - So 01.03.09 13:38

procedure TForm1.Button8Click(Sender: TObject);
var

TestFile: TFileStream;
TestMemStream: TMemoryStream;
i: Integer;
begin
for i := Low(Region) to High(Region) do
begin
Region[i] := Region[i];
Zugehoerigkeit[i] := Zugehoerigkeit[i];
end;

TestFile := TFileStream.Create(SaveDialog1.Filename, fmOpenWrite);
try
TestMemStream := TMemoryStream.Create;
try
// Die Größe des MemoryStreams setzen
TestMemStream.SetSize(Length(Region) * SizeOf(Single));
// Den Speicherbereich des Arrays in den des Streams kopieren
CopyMemory(TestMemStream.Memory, @Region[Low(Region)], Length(Region) * SizeOf(Single));
// Die Position zum Lesen auf den Anfang setzen
TestMemStream.Position := 0;
// Und von dort aus den Inhalt in die Datei kopieren
TestFile.CopyFrom(TestMemStream, TestMemStream.Size);

TestMemStream.SetSize(Length(Zugehoerigkeit) * SizeOf(Byte));
CopyMemory(TestMemStream.Memory, @Zugehoerigkeit[Low(Region)], Length(Zugehoerigkeit) * SizeOf(Byte));
TestMemStream.Position := 0;
TestFile.CopyFrom(TestMemStream, TestMemStream.Size);
finally
TestMemStream.Free;
end;
finally
TestFile.Free;
end;
end;


Delete - So 01.03.09 13:41

Zitat:

Delphi-Quelltext
1:
2:
3:
4:
5:
for i := Low(Region) to High(Region) do
begin
Region[i] := Region[i];
Zugehoerigkeit[i] := Zugehoerigkeit[i];
end;

Ähmm... wozu soll das gut sein? Und Du führst den Dialog ja gar nicht aus.


klausiemausie - So 01.03.09 13:47

öhm gute frage, das stand im beispiel von jaenicke mit region[i]:=i, da das ja nich erwünscht war hab ich das geändert, is eig sinnlos ja^^. wie muss ich den code den ändern, dass er ausgeführt wird?


Delete - So 01.03.09 13:49

Das stand doch bereits in meiner ersten Antwort.

Delphi-Quelltext
1:
2:
3:
4:
5:
if SaveDialog1.Execute then
  begin
    TestFile := TFileStream.Create(SaveDialog1.Filename, fmOpenWrite); 
    // usw.
  end;


klausiemausie - So 01.03.09 14:39

gut das funktioniert, und wie erzähl ich dem savedialog nun, dass er das als ne text datei speichert? weil es kommt jetz die selbe fehlermeldung, allerdings erst wenn ich einen dateinamen eingebe und auf speichern klicke


Keldorn - So 01.03.09 14:42

zeig nochmal deinen aktuellen code und setz den bitte in Delphitags, liest sich besser


klausiemausie - So 01.03.09 14:44


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:
procedure TForm1.Button8Click(Sender: TObject);
var

  TestFile: TFileStream;
  TestMemStream: TMemoryStream;
  i: Integer;
begin
  for i := Low(Region) to High(Region) do
  begin
    Region[i] := Region[i];
    Zugehoerigkeit[i] := Zugehoerigkeit[i];
  end;
if SaveDialog1.Execute then
begin
  TestFile := TFileStream.Create(SaveDialog1.Filename, fmOpenWrite);
  try
    TestMemStream := TMemoryStream.Create;
    try
      // Die Größe des MemoryStreams setzen
      TestMemStream.SetSize(Length(Region) * SizeOf(Single));
      // Den Speicherbereich des Arrays in den des Streams kopieren
      CopyMemory(TestMemStream.Memory, @Region[Low(Region)], Length(Region) * SizeOf(Single));
      // Die Position zum Lesen auf den Anfang setzen
      TestMemStream.Position := 0;
      // Und von dort aus den Inhalt in die Datei kopieren
      TestFile.CopyFrom(TestMemStream, TestMemStream.Size);

      TestMemStream.SetSize(Length(Zugehoerigkeit) * SizeOf(Byte));
      CopyMemory(TestMemStream.Memory, @Zugehoerigkeit[Low(Region)], Length(Zugehoerigkeit) * SizeOf(Byte));
      TestMemStream.Position := 0;
      TestFile.CopyFrom(TestMemStream, TestMemStream.Size);
    finally
      TestMemStream.Free;
    end;
  finally
    TestFile.Free;
  end;

  end;
end;


Keldorn - So 01.03.09 14:55

warum hast Du
Zitat:

for i := Low(Region) to High(Region) do begin Region[i] := Region[i]; Zugehoerigkeit[i] := Zugehoerigkeit[i]; end;
noch drin?

Zitat:

TestFile := TFileStream.Create(SaveDialog1.Filename, fmOpenWrite);


aus der oh:
Zitat:

fmOpenWrite : Die Datei wird ausschließlich zum Schreiben geöffnet. Beim Schreiben in die Datei wird der aktuelle Inhalt vollständig ersetzt.
fmCreate :Es wird eine Datei mit dem angegebenen Namen angelegt. Ist eine Datei mit diesem Namen bereits vorhanden, wird die Datei geleert und zum Schreiben geöffnet.

was meinst Du, was Du verwneden mußt, wenn die Datei noch nicht exisitiert? fmopenwrite oder fmcreate? und warum wirst Du mit openwrite Deine Fehlermeldung erhalten ;-)?

Edit: Achso und als Text-datei wird der stream nicht gespeichert! du kannst das nicht mit einem editor öffnen und bearbeiten.


klausiemausie - So 01.03.09 15:27

schubba, jetz funzt es, danke an alle