Entwickler-Ecke
Dateizugriff - Verständnisfrage zu TStream.Seek
IhopeonlyReader - Mo 02.09.13 13:05
Moderiert von
Narses: Abgetrennt von [url=http://www.entwickler-ecke.de/viewtopic.php?t=111829]hier[/url].
ich habe noch einen Unterschied festgestellt !
Falls man etwas in einem Stream überschreiben will, MUSS man Writebuffer verwenden (vorher Position entsprechend setzten)
Write hängt es hinten dran oder macht gar nix damit :O
Writebuffer überschreibt und fertig :)
Hab ich heute erst bemerkt, denn
Delphi-Quelltext
1: 2: 3: 4:
| FS.Read( aByte, 1 ); aByte := aByte xor Mask; FS.Position := FS.Position -1; FS.WriteBuffer( aByte, 1 ); |
das klappt so, dagegen klappt
Delphi-Quelltext
1: 2: 3: 4:
| FS.Read( aByte, 1 ); aByte := aByte xor Mask; FS.Position := FS.Position -1; FS.Write( aByte, 1 ); |
nicht !
oder gibt es dafür andere erklärungen`?
Blup - Mo 02.09.13 17:55
Wer "Write" verwendet muss immer den Rückgabewert auswerten (sonst kann man nur raten wie das Ergebnis zustande kommt).
Abhängig vom Stream eventuell auch noch LastError.
Das sollte man besser dem Stream selbst überlassen, sonst schafft man unnötige Abhängigkeiten.
rushifell - Di 03.09.13 00:39
Bist du Dir sicher, dass das Offset zum Lesen und Schreiben korrekt ist?
Kennst Du die Methode 'seek'?
IhopeonlyReader - Mi 04.09.13 10:39
ob seek( x ) oder Position := x; ich merke keinen unterschied !
jaenicke - Mi 04.09.13 13:30
Das könnte daran liegen, dass Position intern auch nur Seek verwendet. ;-)
rushifell - Mi 04.09.13 17:05
Warum sollte das im Ergebnis einen Unterschied machen? Habe ich nie behauptet.
Habe mich nur gewundert, dass Du die Position so umständlich setzt.
Martok - Mi 04.09.13 18:02
Hach ist hier viel Halbwissen. Use the source, Luke!
Delphi-Quelltext
1: 2: 3: 4: 5:
| procedure TStream.WriteBuffer(const Buffer; Count: Longint); begin if (Count <> 0) and (Write(Buffer, Count) <> Count) then raise EWriteError.CreateRes(@SWriteError); end; |
:arrow: einziger Unterschied ist eine Exception wenn's nicht klappt.
IhopeonlyReader hat folgendes geschrieben : |
ob seek( x ) oder Position := x; ich merke keinen unterschied ! |
Doch, da ist einer. Ein Lesezugriff auf Position ist ein
Seek(0, soFromCurrent), ein Schreibzugriff
Seek(aValue, soFromBeginning). Verwendest du das Property, sind da zwei Dateioperationen,
Seek(-1, soFromCurrent) direkt aufzurufen ist also schneller. Wenn man das ein paar tausend mal macht, fällt das schon (natürlich auch abhängig von der Streamklasse) auf.
IhopeonlyReader - Mi 04.09.13 18:16
Martok hat folgendes geschrieben : |
Hach ist hier viel Halbwissen. Use the source, Luke!
Delphi-Quelltext 1: 2: 3: 4: 5:
| procedure TStream.WriteBuffer(const Buffer; Count: Longint); begin if (Count <> 0) and (Write(Buffer, Count) <> Count) then raise EWriteError.CreateRes(@SWriteError); end; |
|
wenn das so wäre, was ich gerne glaube, würde ich gerne eine Erklärung haben, warum es mit write nicht funktioniert, mit writebuffer schon !
rushifell - Mi 04.09.13 19:22
Deshalb habe ich geschrieben, das es im "Ergebnis" keinen Unterschied macht. Beides funktioniert. Dass Position intern Seek aufruft, hat ja bereits Jaenicke geschrieben. Dass es daher mehr Sinn macht, direkt Seek zu verwenden ist dadurch ja klar.
In den Personal Editions gibt's leider keinen Source.
IhopeonlyReader - Mi 04.09.13 20:24
ich meinte Write und Writebuffer.. Writebuffer funktioniert, write alleine nicht
jaenicke - Mi 04.09.13 20:52
Ohne ein konkret funktionierendes Beispielprojekt wird da wohl niemand mehr dazu sagen können. Bei mir haben Write und WriteBuffer immer funktioniert wie sie sollen. :nixweiss:
IhopeonlyReader - Mi 04.09.13 21:22
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| var aByte, Mask: Byte; C: Integer; FS: TFileStream; begin FS := TFileStream.Create( aFileName, fmOpenReadWrite or fmShareDenyRead or fmShareDenyWrite ); try FS.Position := 0; For C := 1 to FS.Size do begin
FS.Read( aByte, 1 ); aByte := aByte xor Mask; Seek( FS.Position -1 , soFromBeginning ); FS.WriteBuffer( aByte, 1 ); end; finally FS.Free; end; end; |
aber als ich jetzt Write verwendete funktionierte es, mein Delphi spinnt öfter mal :(
Delphi neustarten lässt write plötzlich auch in der compilierten exe funktionieren :)
Und bei einem anderen Programm habe ich sogar das Problem, dass sich meine Form nicht enabled obwohl ich sie nie disable :O Meine Form wird also nicht ansprechbar, bei allen anderen Projekten funktionierts, nur da nicht... es liegt ganz sicher kein fehler vor ! Aber ich muss wohl wieder 2-3 tage warten und dann Wunder funktionierts wieder..
jaenicke - Mi 04.09.13 22:11
:shock:
Vor dem Seek hast du das FS vergessen. Dass das nicht geht, ist klar...
Wie wärs einfach so...
Delphi-Quelltext
1:
| FS.Seek(-1, soFromCurrent); |
rushifell - Mi 04.09.13 22:20
Zeile 8 ist überflüssig, einfach weglassen. Und wenn du FS.Read verwendest, musst du den Rückgabewert überprüfen.
Eine For-Schleife zu verwenden, wäre mir auch nicht geheuer.
IhopeonlyReader - Mi 04.09.13 22:46
ja, eigentlich steht da
FS.Position := FS.Position -1;
aber ich wollte es auf "eure" Vorschläge schonmal anpassen..
Ob Zeile 8 überflüssig ist, weiß ich nicht. Lieber initialisieren ;)
und warum soll eine For-Schleife nicht geheuer sein? Ich gehe Byte für Byte durch, dass ich das genau so oft mache, wie viele Bytes enthalten sind ist doch logisch oder?
Bei Read und Write überprüfe ich keine Rückgabewerte ! Es wird das gemacht, was möglich ist.
Wenn ich ein 2tes mal mache, wird es ebenso nicht möglich sein, und somit macht es kein Unterschied ! ggf. könnte ich, falls der positionszeiger nicht aktualisiert wird, da das schreiben/lesen nicht geklappt hat, diesen einen weiter setzten, sonst versucht er immer an der "nicht möglich" stelle zu lesen, aber wenn ich gehe davon aus, dass alles oder nichts klappt. ich kenne keine Datei die nur zulässt Byte 1-X und ab X+1 zu beschreiben..
rushifell - Mi 04.09.13 23:11
Du bist sehr beratungsresistent. ;-)
Gerd Kayser - Mi 04.09.13 23:27
IhopeonlyReader hat folgendes geschrieben : |
Falls man etwas in einem Stream überschreiben will, MUSS man Writebuffer verwenden (vorher Position entsprechend setzten) |
Das ist falsch, denn das hier funktioniert:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| procedure TMainform.Button1Click(Sender: TObject); var FS : TFileStream; Schleife : Integer; Wert : Byte; Maske : Byte; begin FS := TFileStream.Create('f:\x.xxx', fmCreate); try Wert := 65; for schleife := 1 to 100 do FS.Write(Wert, SizeOf(Wert)); FS.Position := FS.Position - 1; FS.Read(Wert, 1); Maske := 122; Wert := Wert XOR Maske; FS.Position := FS.Position - 1; FS.Write(Wert, SizeOf(Wert)); finally FS.Free; end; end; |
IhopeonlyReader - Do 05.09.13 13:41
Gerd Kayser hat folgendes geschrieben : |
IhopeonlyReader hat folgendes geschrieben : | Falls man etwas in einem Stream überschreiben will, MUSS man Writebuffer verwenden (vorher Position entsprechend setzten) |
Das ist falsch, denn das hier funktioniert: |
aber als ich jetzt Write verwendete funktionierte es, mein Delphi spinnt öfter mal :( (sagte ich schonmal)
rushifell hat folgendes geschrieben : |
Du bist sehr beratungsresistent. ;-) |
Naja, deine Aussage
Zitat: |
Eine For-Schleife zu verwenden, wäre mir auch nicht geheuer.
|
sagt soviel wie, "ich würde eine andere schleife verwenden"
da ich sonst nur while und repeat kenne und diese langsamer sind frage ich mich, warum ich while oder repeat benutzen sollte, ich weiß doch wieviele Bytes ich durchgehen muss...
Zu dem "FS vergessen" habe ich auch ausgesagt, dass das eine Anpassung war und nicht direkt die Fehlerquelle..
jaenicke - Do 05.09.13 13:46
IhopeonlyReader hat folgendes geschrieben : |
aber als ich jetzt Write verwendete funktionierte es, mein Delphi spinnt öfter mal :( (sagte ich schonmal) |
Delphi spinnt da sicher nicht mal und mal nicht. Solange du nicht gerade Speicherprobleme hast, sprich an Stellen geschrieben hast, die nicht zum Schreiben waren, kann das nicht sein.
Wenn du debuggst und dabei im Debugger auf die Werte schauen willst, solltest du die Optimierung in den Projektoptionen deaktivieren. Das Verhalten mit Optimierung kann im Debugger schon mal komisch aussehen. ;-)
rushifell - Do 05.09.13 17:42
Wo hast Du das aufgeschnappt, dass man nach dem Erzeugen eines Streams die Position auf 0 bzw. den Anfang setzen muss? Hab ich noch nie gesehen, lass mich aber gerne eines Besseren belehren.
Wenn Du die Rückgabewerte nicht prüfst, ist das zumindest meiner Meinung nach schlechter Programmierstil. Dann nimm lieber ReadBuffer.
Nicht alles, was funktioniert ist gut. Die For-Schleife ist schon in Ordnung. Warum soll aber die For-Schleife schneller sein? Hast Du Beweise dafür?
IhopeonlyReader - Do 05.09.13 17:57
rushifell hat folgendes geschrieben : |
Wo hast Du das aufgeschnappt, dass man nach dem Erzeugen eines Streams die Position auf 0 bzw. den Anfang setzen muss? Hab ich noch nie gesehen, lass mich aber gerne eines Besseren belehren. |
ich bin selbstbeibringer und ich habe mich "gezwungen" alles was ich irgendwo erstelle zu initialisieren. Das führt dazu, dass ich z.B. bei einer verketteten liste auch den Pointer vom next auf Nil setzte
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| NextPart := TNextPart.create; NextPart.Content := NewContent; NextPart.Next := Nil; Tail.Next := NextPart; Tail := Tail.next; |
rushifell hat folgendes geschrieben : |
Wenn Du die Rückgabewerte nicht prüfst, ist das zumindest meiner Meinung nach schlechter Programmierstil. Dann nimm lieber ReadBuffer. |
Ich habe nun, falls der Rückgabewert ungleich 1 ist dieses "übersprungen".. Fehlermeldungen gib ich ungern aus, da dann meist nicht 1 sondern gefühlte 1000 kommen...
da das Programm nur für mich ist, wird es auch keinen geben, der von fehlenden Fehlermeldungen genervt sein will...
rushifell hat folgendes geschrieben : |
Nicht alles, was funktioniert ist gut. Die For-Schleife ist schon in Ordnung. Warum soll aber die For-Schleife schneller sein? Hast Du Beweise dafür? |
MeierZwoo hat folgendes geschrieben: |
WHILE und REPEAT/UNTIL nehmen sich nichts, sind aber (grade beim schnellen Tippseln für einen Zeittest) kritisch, weil die Abbruchbedingung unbedingt erreicht werden muß (Die man ja auch meist nicht hat und nachher nicht weiss, wie oft durchlaufen - es sei denn, man schreibt dies noch zusätzich mit).
Eine FOR Schleife wäre schneller, weil dort nur ein Wert erhöht werden und keine Abbruchbedingung ermittelt werden muß. Außerdem hat man bei FOR gleich den Teiler für die Zeitmessung. |
aus dem Thread :
http://www.entwickler-ecke.de/viewtopic.php?t=111508
rushifell - Do 05.09.13 18:39
Schau Dir doch einfach mal die Online-Hilfe von Delphi an, dort gibt es in der Regel auch Beispiele. Ich müsste wirklich sehr täuschen, wenn es notwendig wäre, die Position auf 0 zu setzen.
Das mit der For-Schleife ist nur eine Behauptung von einer Person, woher weisst Du, dass diese Behauptung stimmt? Im Idealfall vielleicht schon. Achtung, sonst werden wir zu Off-Topic.
Bei einem Fehler in der For-Schleife kannste die Schleife mit Break abbrechen/beenden.
jaenicke - Do 05.09.13 22:50
rushifell hat folgendes geschrieben : |
Das mit der For-Schleife ist nur eine Behauptung von einer Person, woher weisst Du, dass diese Behauptung stimmt? Im Idealfall vielleicht schon. |
Das ist auch so, allerdings ist der Unterschied bei wenigen Durchläufen nicht spürbar. Im Anhang ein Vergleich, die in der Schleife wiederholten Zeilen sind rot markiert.
Man sieht, dass bei der for-Schleife die Initialisierung vorher passiert, so dass dort 4 Assemblerbefehle mehr gebraucht werden als bei der while-Schleife. Dafür werden bei der while-Schleife 2 Assemblerbefehle mehr bei jedem Durchlauf benötigt.
Heißt: while ist ab drei Durchläufen langsamer. ;-)
rushifell - Fr 06.09.13 02:18
Danke jaenicke, so wie Du's beschrieben hast, ist es auch nachvollziehbar. Und das trifft auch zu, wenn in der For-Schleife eine Abbruchbedingung vorhanden ist?
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| FOR i:=0 to FS.Count-1 Do Begin ... Numread:=FS.Read(b,1); IF Numread<>1 then Break; end; |
Kann mir Dein Beispiel leider erst am Montag anschauen. Bin z.Z. leider nur mobil im Netz.
jaenicke - Fr 06.09.13 08:27
rushifell hat folgendes geschrieben : |
Danke jaenicke, so wie Du's beschrieben hast, ist es auch nachvollziehbar. Und das trifft auch zu, wenn in der For-Schleife eine Abbruchbedingung vorhanden ist? |
Das ist etwas anderes. Die for-Schleife ist unter der Voraussetzung schneller, dass man vorher weiß wie viele Durchläufe es gibt. Wenn man hingegen eine Abbruchbedingung prüft, sind das natürlich zusätzliche Befehle. Wenn man diese Prüfung auch als Schleifenbedingung benutzen könnte, macht while/repeat mehr Sinn, da diese Prüfung ja nicht bei for wegfällt und somit die Prüfungen der for-Schleife zusätzlich sind.
Ist hingegen die normale Anzahl der Durchläufe vorgegeben und das andere nur eine zusätzliche Bedingung ist weiter eher for schneller, wobei man da im Einzelfall schauen müsste wie der Compiler das optimiert. In der Regel sollte das aber nur die Prüfung und ein Sprung sein, und das wäre dann in der while-Schleifenbedingung genauso, so dass die gesparten Befehle bei for weiter ein Vorteil sind.
Nebenbei:
Wenn man die Anzahl der Durchläufe kennt, ist for auch übersichtlicher, da man dies bei fremdem Quelltext sofort erkennt. Bei einer while- oder repeat-Schleife muss man erst in der Schleife schauen wann diese abbricht usw., so dass man mehr Zeit braucht um den Quelltext zu überblicken.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2024 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!