| Autor |
Beitrag |
patrick
      
Beiträge: 1481
WIN2k, WIN XP
D6 Personal, D2005 PE
|
Verfasst: 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.
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?
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| repeat
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
Delphi-Quelltext 1:
| mstream.Read(result,mstream.Size-sizeof(string)); |
hab ich es auch schon mit
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
      
Beiträge: 997
|
Verfasst: 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:
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:
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 Tino: Code- durch Delphi-Tags ersetzt.
_________________ Life is a bad adventure, but the graphic is really good!
|
|
patrick 
      
Beiträge: 1481
WIN2k, WIN XP
D6 Personal, D2005 PE
|
Verfasst: So 06.07.03 12:28
ich werds (vielleicht) heute mal versuchen wenn ich dazu komme...
_________________ Patrick
im zweifelsfall immer das richtige tun!!!
|
|
patrick 
      
Beiträge: 1481
WIN2k, WIN XP
D6 Personal, D2005 PE
|
Verfasst: 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
      
Beiträge: 997
|
Verfasst: 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 
      
Beiträge: 1481
WIN2k, WIN XP
D6 Personal, D2005 PE
|
Verfasst: 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:
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
      
Beiträge: 997
|
Verfasst: 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 
      
Beiträge: 1481
WIN2k, WIN XP
D6 Personal, D2005 PE
|
Verfasst: 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 
      
Beiträge: 1481
WIN2k, WIN XP
D6 Personal, D2005 PE
|
Verfasst: 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  , 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
      
Beiträge: 997
|
Verfasst: Mo 14.07.03 17:57
Hallo,
hier ein kleiner Code:
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
      
Beiträge: 997
|
Verfasst: Mo 14.07.03 18:56
Hallo nochmal,
sorry, Comments vergessen
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 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; |
Ich denke, jetzt müsste alles ersichtlich sein.
_________________ Life is a bad adventure, but the graphic is really good!
|
|
AndyB
      
Beiträge: 1173
Erhaltene Danke: 14
RAD Studio XE2
|
Verfasst: 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. [...]
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 
      
Beiträge: 1481
WIN2k, WIN XP
D6 Personal, D2005 PE
|
Verfasst: Di 15.07.03 12:03
@Andreas Pfau THX
@ AndyB von einer funktion
_________________ Patrick
im zweifelsfall immer das richtige tun!!!
|
|
AndyB
      
Beiträge: 1173
Erhaltene Danke: 14
RAD Studio XE2
|
Verfasst: 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.
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;
|
_________________ Ist Zeit wirklich Geld?
Zuletzt bearbeitet von AndyB am Di 15.07.03 13:55, insgesamt 1-mal bearbeitet
|
|
AndyB
      
Beiträge: 1173
Erhaltene Danke: 14
RAD Studio XE2
|
Verfasst: 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.
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); 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)); SetLength(S, Len); end; if ValueLen > 0 then begin Move(S[RealLen + 1], Value[1], ValueLen); Inc(RealLen, ValueLen); end; end; SetLength(S, RealLen); |
_________________ Ist Zeit wirklich Geld?
|
|
patrick 
      
Beiträge: 1481
WIN2k, WIN XP
D6 Personal, D2005 PE
|
Verfasst: Mi 16.07.03 12:49
danke ich werde beides ausprobieren... 
_________________ Patrick
im zweifelsfall immer das richtige tun!!!
|
|
|