Autor Beitrag
patrick
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 1481

WIN2k, WIN XP
D6 Personal, D2005 PE
BeitragVerfasst: Sa 05.07.03 12:26 
hallo zusammen,
ich arbeite gerade zum ersten mal richig mit memorystreams und
meine bücher können mir nicht so richtig weiterhelfen. :cry:

ich habe in meinem programm eine funktion welche in eine repeat-schleife kleine wörter(strings) mit einer länge zwischen 1 und 5 zeichen erstellt.
diese erstellten wörter sollen anschleißend zu den anderen (davor erstellten wörtern) in dem memorystream hinzugefügt werden.

wenn die schleife beendet wurde, soll der gesamte inhalt des streams in die variable result ausgelesen werden, welche anschließend in ein memo-feld kopiert wird.

leider funktioniert der unten stehende quelltext nicht.
(es sei den sinn des codes wäre gewesen eine access violation hervorzurufen!)
wo liegt mein (denk)-fehler?

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
repeat
{...
erstellung der wörter 
das resultat wird in der variable "tmp" gespeichert
...}

mstream.Write(tmp,(sizeof(tmp)*length(tmp));
inc(current);
until
(max=current) or
(GetAsyncKeystate(Vk_Escape) <> 0);

mstream.Position:=0;
mstream.Read(result,mstream.Size);
mstream.Clear;
mstream.Free;


statt mit
ausblenden Delphi-Quelltext
1:
mstream.Read(result,mstream.Size-sizeof(string));					

hab ich es auch schon mit
ausblenden Delphi-Quelltext
1:
memo1.lines.readfromstream(mstream)					

probiert aber als ergebnis kommen nur bruchstücke des ursprünglichen codes herraus (bei 1000 druchläufen nur 2 zeichen!)
obwohl mstream.Size die richtige größe hatte.

ich hoffe mir kann jemand helfen
THX

_________________
Patrick
im zweifelsfall immer das richtige tun!!!


Zuletzt bearbeitet von patrick am Mi 23.07.03 09:29, insgesamt 1-mal bearbeitet
Andreas Pfau
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 997



BeitragVerfasst: Sa 05.07.03 20:38 
Hallo,

so wie ich das verstehe willst du einen String (Deklariert als "STRING") in einen Stream schreiben. Nöö, geht net. Warum? Ein string enthält keine Daten. Das ist eigentlich nur ein Zeiger, also 32Bit, die auf den Speicherbereich verweisen, wo der eigentliche Text ist. Du musst also die Daten UND deren Länge hinterlegen. So:
ausblenden Delphi-Quelltext
1:
2:
3:
Len := Length(Str);
Stream.Write(Len, SizeOf(Len));
StreamWrite(Pointer(Str)^, Len);

Warum ich den String so komisch in Pointer umwandle? Anders macht dir der Compiler Stress! OK, und so liest man:
ausblenden Delphi-Quelltext
1:
2:
3:
Stream.Read(Len, SizeOf(Len));
SetLength(Str, Len);
Stream.Read(Pointer(Str)^, Len);

Ready. War es das, was du wolltest?

Moderiert von user profile iconTino: Code- durch Delphi-Tags ersetzt.

_________________
Life is a bad adventure, but the graphic is really good!
patrick Threadstarter
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 1481

WIN2k, WIN XP
D6 Personal, D2005 PE
BeitragVerfasst: So 06.07.03 12:28 
ich werds (vielleicht) heute mal versuchen wenn ich dazu komme...

_________________
Patrick
im zweifelsfall immer das richtige tun!!!
patrick Threadstarter
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 1481

WIN2k, WIN XP
D6 Personal, D2005 PE
BeitragVerfasst: Do 10.07.03 18:48 
ist es möglich den gesamten vorher häppchenweise eingelesenen string auf einmal auszulesen?
beipiel:
ich schreibe in den stream drei mal daten:
teil_eins_
teil_zwei_
teil_drei_

und möchte den gesamten stream nun auf einen schlag auslesen so das dies anschließen so aussieht:
teil_eins_teil_zwei_teil_drei

geht das?

_________________
Patrick
im zweifelsfall immer das richtige tun!!!
Andreas Pfau
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 997



BeitragVerfasst: Do 10.07.03 19:14 
Hallo,

entweder du liest die 3 Teile ainzeln aus und setzt sie zusammen, oder, was ich tun würde, sie vorher in einen einzelnen Stream zusammensetzen, dann als einzelnen String streamen.[/code]

_________________
Life is a bad adventure, but the graphic is really good!
patrick Threadstarter
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 1481

WIN2k, WIN XP
D6 Personal, D2005 PE
BeitragVerfasst: Fr 11.07.03 10:49 
genau das wollte ich ja vermeiden:
das programm macht ca 10000-20000 durchläufe wo es einen kleinen string an die anderen, davor erstellten strings, anknüpft.
dies hab ich zuerst so geregelt:

ausblenden Delphi-Quelltext
1:
gesamt_string:=gesamt_string+teilstring;					

nachteil: je länger die durchläufe dauern, desto langsamer wird das programm, da der string immer länger wird.

deshalb wollte ich die ganzen einzelstrings in den stream laden und nach beendigung der schleife den gesamten stream auf einmal auslesen.

_________________
Patrick
im zweifelsfall immer das richtige tun!!!
Andreas Pfau
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 997



BeitragVerfasst: Fr 11.07.03 13:21 
Hallo,

dann mach es so:
- schreib zuerst die Länge ALLER Strings rein (Length(S1) + Length...)
- Dann String1, String2, String3 einzeln schreiben, ohne weitere Längenangabe

Dann kannst du es auf einen Rutsch auslesen, als ob#s nur einer Wäre.

_________________
Life is a bad adventure, but the graphic is really good!
patrick Threadstarter
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 1481

WIN2k, WIN XP
D6 Personal, D2005 PE
BeitragVerfasst: Mo 14.07.03 12:32 
ich werd es irgendwann diese woche versuche, hab viel um die ohren
*sorry*

_________________
Patrick
im zweifelsfall immer das richtige tun!!!
patrick Threadstarter
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 1481

WIN2k, WIN XP
D6 Personal, D2005 PE
BeitragVerfasst: Mo 14.07.03 17:51 
Andreas Pfau hat folgendes geschrieben:
Hallo,

dann mach es so:
- schreib zuerst die Länge ALLER Strings rein (Length(S1) + Length...)
- Dann String1, String2, String3 einzeln schreiben, ohne weitere Längenangabe

Dann kannst du es auf einen Rutsch auslesen, als ob#s nur einer Wäre.


ich kriegs nicht hin :cry: , kannst du mir den quelltext mal vorgeben?
ne kleine erklärung zum quelltext wäre auch nicht schlecht damit ich nicht ewig dumm bleibe :(

_________________
Patrick
im zweifelsfall immer das richtige tun!!!
Andreas Pfau
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 997



BeitragVerfasst: Mo 14.07.03 17:57 
Hallo,

hier ein kleiner Code:
ausblenden volle Höhe 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:
procedure TMain.Button1Click(Sender: TObject);
var
  F: TFileStream;
  S1, S2, S3: string;
  Len: Integer;
begin
  S1 := 'Ein';
  S2 := ' kleines';
  S3 := ' Beispiel.';
  Len := Length(S1) + Length(S2) + Length(S3);

  F := TFileStream.Create('Test.dat', fmCreate);
  F.Write(Len, SizeOf(Len));
  F.Write(Pointer(S1)^, Length(S1));
  F.Write(Pointer(S2)^, Length(S2));
  F.Write(Pointer(S3)^, Length(S3));
  F.Free;
end;

procedure TMain.Button2Click(Sender: TObject);
var
  F: TFileStream;
  S: string;
  Len: Integer;
begin
  F := TFileStream.Create('Test.dat', fmOpenRead);
  F.Read(Len, SizeOf(Len));
  SetLength(S, Len);
  F.Read(Pointer(S)^, Length(S));
  F.Free;

  ShowMessage(S);
end;


Button1.Click -> Schreiben
Button2.Click -> Lesen

Noch Fragen :?:

_________________
Life is a bad adventure, but the graphic is really good!
Andreas Pfau
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 997



BeitragVerfasst: Mo 14.07.03 18:56 
Hallo nochmal,

sorry, Comments vergessen :oops:

ausblenden volle Höhe 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:
procedure TMain.Button1Click(Sender: TObject);
var
  F: TFileStream;
  S1, S2, S3: string;
  Len: Integer;
begin
  // Strings setzen
  S1 := 'Ein';
  S2 := ' kleines';
  S3 := ' Beispiel.';

  // Länge der Strigns auslesen und addieren
  Len := Length(S1) + Length(S2) + Length(S3);

  // Stream erzeugen
  F := TFileStream.Create('Test.dat', fmCreate);

  // Gesamtlänge schreiben
  F.Write(Len, SizeOf(Len));

  // Einzelne Strings schreiben
  F.Write(Pointer(S1)^, Length(S1));
  F.Write(Pointer(S2)^, Length(S2));
  F.Write(Pointer(S3)^, Length(S3));

  // Stream freigeben
  F.Free;
end;

procedure TMain.Button2Click(Sender: TObject);
var
  F: TFileStream;
  S: string;
  Len: Integer;
begin
  // Stream erzeugen
  F := TFileStream.Create('Test.dat', fmOpenRead);

  // Länge auslesen
  F.Read(Len, SizeOf(Len));

  // Länge des Strings setzen
  SetLength(S, Len);

  // String auslesen
  F.Read(Pointer(S)^, Length(S));

  // Stream freigeben
  F.Free;

  // Gelesenen Stream anzeigen
  ShowMessage(S);
end;


Ich denke, jetzt müsste alles ersichtlich sein.

_________________
Life is a bad adventure, but the graphic is really good!
AndyB
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1173
Erhaltene Danke: 14


RAD Studio XE2
BeitragVerfasst: Mo 14.07.03 20:05 
patrick hat folgendes geschrieben:
das programm macht ca 10000-20000 durchläufe wo es einen kleinen string an die anderen, davor erstellten strings, anknüpft. [...]
ausblenden Delphi-Quelltext
1:
gesamt_string:=gesamt_string+teilstring;					

Du misshandelst damit den Speichermanager und der revanchiert sich mit einem extremen Speicherverbauch. Das kann sogar mehr als 200 MB Ram verschlingen obwohl du nur 1 MB Daten hast.

Zitat:
nachteil: je länger die durchläufe dauern, desto langsamer wird das programm, da der string immer länger wird.

Das das Syntom der Misshandlung. Windows muss jedes zusätzliche Byte in das PageFile schreiben und auch wieder auslesen. Und da die Festplatte im Vergleich zum RAM sehr sehr langsam ist, wird dein Programm eben auch langsamer.


Zitat:
deshalb wollte ich die ganzen einzelstrings in den stream laden und nach beendigung der schleife den gesamten stream auf einmal auslesen.

Damit schiebst du die Misshandlung von den Stringfunktionen auf die Streamfunktionen. Im Endeffekt nimmt dadurch der Speicherverbrauch sogar noch stärker zu.



Woher bekommst du die Teilstrings? Aus einer StringList, aus einer Datei, von einer Funktion?

_________________
Ist Zeit wirklich Geld?
patrick Threadstarter
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 1481

WIN2k, WIN XP
D6 Personal, D2005 PE
BeitragVerfasst: Di 15.07.03 12:03 
@Andreas Pfau THX :D


@ AndyB von einer funktion

_________________
Patrick
im zweifelsfall immer das richtige tun!!!
AndyB
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1173
Erhaltene Danke: 14


RAD Studio XE2
BeitragVerfasst: Di 15.07.03 13:48 
Braucht diese Funktion lange, bis sie den String zurückliefert? Wenn nicht, dann solltest du zuerst die Länge aller Strings zusammen ermitteln und dann mit SetLength() den Zielstring auf die Gesamtlänge setzen. Danach kannst du mit Move() und einem PChar die Zeichen kopieren.
Bei wenigen Strings ist dies zwar erheblich langsamer, aber wenn du dann auf über 1000 Stringzusammensetzungen kommst, dreht sich der Geschwindigkeitsgewinn um.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
MaxLen := 0;
for i := 0 to Anzahl - 1 do
  MaxLen := MaxLen + Length(Funktion(i));

SetLength(S, MaxLen);

if MaxLen > 0 then
begin
  P := PChar(S);
  for i := 0 to Anzahl - 1 do
  begin
    Value := Funktion(i);
    if Value <> '' then
    begin
      Move(Value[1], P^, Length(Value));
      Inc(P, Length(Value));
    end;
  end;
end;

// hier steht S zur Verfügung.

_________________
Ist Zeit wirklich Geld?


Zuletzt bearbeitet von AndyB am Di 15.07.03 13:55, insgesamt 1-mal bearbeitet
AndyB
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1173
Erhaltene Danke: 14


RAD Studio XE2
BeitragVerfasst: Di 15.07.03 13:55 
Braucht die Funktion hingegen lange, dann musst du einen Pauschalwert für die Länge des Strings benutzen, den du dann immer um ein gewisses Maß verlängerst.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
RealLen := 0;
Len := 1024 * 1024;
SetLength(S, Len); // 1 MB

for i := 0 to Anzahl - 1 do
begin
  Value := Funktion(i);

  ValueLen := Length(Value);
  if RealLen + ValueLen > Len then
  begin
    Inc(Len, Max(1024 * 1024, ValueLen)); // mindestens 1 weiteres MB reservieren
    SetLength(S, Len);
  end;
  if ValueLen > 0 then
  begin
    Move(S[RealLen + 1], Value[1], ValueLen);
    Inc(RealLen, ValueLen);
  end;
end;
SetLength(S, RealLen); // S auf die wahre Länge kürzen

_________________
Ist Zeit wirklich Geld?
patrick Threadstarter
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 1481

WIN2k, WIN XP
D6 Personal, D2005 PE
BeitragVerfasst: Mi 16.07.03 12:49 
danke ich werde beides ausprobieren... :D

_________________
Patrick
im zweifelsfall immer das richtige tun!!!