Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Stream auslesen (https://www.delphipraxis.net/62801-stream-auslesen.html)

PASST 9. Feb 2006 18:00


Stream auslesen
 
Hi NG.

Delphi 4 (update 3)

Ich versuche gerade zu verstehen, wie ich Daten aus einem Stream auslesen kann.
Dazu habe ich folgenden Beitrag gefunden, insb. ->Antwort#15. Dort hat SirThornberry Code als Bsp. gepostet. Dabei verstehe ich das Auslesen nicht.
Delphi-Quellcode:
SetLength(LBuffer2, 50);
LBytes := AStream.Read(LBuffer2[1], 50);
LBuffer := copy(LBuffer2, 1, LBytes);
Dass es funktioniert, habe ich durch Nachbauen festgestellt. Mir fehlt es aber anscheinend an Grundlagen.
Warum muss ich für LBuffer2 die Länge vordefinieren? Im Read wird doch vorgegeben, dass ich 50 Bytes lesen will.
Warum muss ich anschließend das ganze in eine zweite Variable LBuffer umkopieren? Wenn das Read weniger als 50 Bytes liefert, also LBytes, macht das schon Sinn. Aber was ist, wenn das Stream ausreichend Bytes enthält?

Ihr merkt, ich bin bzgl Stream und Zeiger ein Anfänger. Ich habe mir auch schon das Tutorial auf DSDT.info dazu durchgelesen, komme aber immer noch nicht wirklich damit zurecht.

Klärt mich bitte auf :cry:
Gruß
Peter

Khabarakh 9. Feb 2006 18:06

Re: Stream auslesen
 
Zitat:

Zitat von PASST
Warum muss ich für LBuffer2 die Länge vordefinieren? Im Read wird doch vorgegeben, dass ich 50 Bytes lesen will.

Der Stream kann aber nicht wissen, dass du einen String übergibst und deshalb nicht SetLength selbst aufrufen. Für das "Auffangbecken" bist du selbst zuständig.
Zitat:

Warum muss ich anschließend das ganze in eine zweite Variable LBuffer umkopieren? Wenn das Read weniger als 50 Bytes liefert, also LBytes, macht das schon Sinn.
Genau.
Zitat:

Aber was ist, wenn das Stream ausreichend Bytes enthält?
Dann wird der String eben sinnlos herumkopiert, ist das denn so schlimm :wink: ?

PASST 9. Feb 2006 18:24

Re: Stream auslesen
 
Zitat:

Der Stream kann aber nicht wissen, dass du einen String übergibst und deshalb nicht SetLength selbst aufrufen.
Dafür deklariere ich LBuffer doch vorher als String.
Wenn ich nicht mit Streams arbeite, gebe ich doch bei einer String-Variable auch nicht vorher die Länge vor, sondern setze einfach: sText := 'Abc'

Zitat:

Dann wird der String eben sinnlos herumkopiert, ist das denn so schlimm?
Nein, schlimm ist das nicht. Aber ich erhalte in jedem Fall einen RuntimeError, wenn ich auf das Kopieren verzichte - obwohl ausreichend Bytes vorhanden sind.

Luckie 9. Feb 2006 18:47

Re: Stream auslesen
 
Zitat:

Zitat von PASST
Zitat:

Der Stream kann aber nicht wissen, dass du einen String übergibst und deshalb nicht SetLength selbst aufrufen.
Dafür deklariere ich LBuffer doch vorher als String.

Jupp und damit ist das Auffangbecken nur als Name vorhanden. Und Namen sind ja bekanntlich nur Schall und Rauch. ;) Wenn du in so ein Auffangbecken was reinschüttest, schüttest du es ins nichts. Mit dem Aufruf von SetLength gibst du dem Auffangbecken jetzt ein Größe und du kannst was reinschütten. Und das geht weil ein String auch nur ein dynamisches Array vom Typ Char ist mit etwas Primboriom zum Verwalten (Länge etc.) drumrum. In ein dynamisches Array der Länge null kannst du auch nichts reinschreiben.

PASST 9. Feb 2006 19:59

Re: Stream auslesen
 
Was ist denn dann der Unterschied zwischen der Verwendung eines String auf diese Weise [sText := 'Abc'] oder wie ich es für ein Stream machen muss?

Luckie 9. Feb 2006 20:03

Re: Stream auslesen
 
Die Methode Read erwartet einen Zeiger auf eine Speicheradresse und wie Khabarakh schon sagt:
Zitat:

Der Stream kann aber nicht wissen, dass du einen String übergibst und deshalb nicht SetLength selbst aufrufen.
Bei der Zuweisung einer Zeichenkette an eine Stringvariable kann der Compiler intern SetLength aufrufen, weil er weiß, dass es sich um einen String handelt - du hast es ja selber so deklariert.

Khabarakh 9. Feb 2006 20:07

Re: Stream auslesen
 
Zitat:

Zitat von PASST
Was ist denn dann der Unterschied zwischen der Verwendung eines String auf diese Weise [sText := 'Abc'] oder wie ich es für ein Stream machen muss?

Der Stream schreibt ab dem übergebenen Pointer munter in den Speicher. Wo dein String aufhört, ist ihm egal, er kann es ja gar nicht wissen. Falls nicht sowieso eine AV ausgelöst wird, kannst du eben über den String nur auf den Teil innerhalb des Strings zugreifen. Hinterher SetLength aufzurufen würde übrigens auch nichts bringen, da ein komplett anderer Speicherplatz für den neuen String verwendet wird.
Das Literal wird vom Compiler zur Compiletime ausgewertet. Es wird sozusagen eine Konstante angelegt, die Zeichenkette auf die Länge analysiert und das Literal mit genau dieser Länge erstellt.

[edit] Der rote Kasten hat mich verlassen :cry: [/edit]

Luckie 9. Feb 2006 20:10

Re: Stream auslesen
 
Zitat:

Zitat von Khabarakh
[edit] Der rote Kasten hat mich verlassen :cry: [/edit]

Macht nichts, war doch eine schöne Ergänzung zu meinem Posting. ;)

Khabarakh 9. Feb 2006 20:21

Re: Stream auslesen
 
Zitat:

Zitat von Luckie
Zitat:

Zitat von Khabarakh
[edit] Der rote Kasten hat mich verlassen :cry: [/edit]

Macht nichts, war doch eine schöne Ergänzung zu meinem Posting. ;)

Dann hätte ich meinen Post aber noch besser auf deinen abstimmen können :zwinker: .

SirThornberry 9. Feb 2006 20:21

Re: Stream auslesen
 
im übrigen ist folgendes effektiver:
Delphi-Quellcode:
SetLength(LBuffer1, 50);
LBytes := AStream.Read(LBuffer1[1], 50);
SetLength(LBuffer, LBytes);
Ich versuch das ganze auch mal zu erklären.
"AStream.Read" macht intern nicht etwa eine Zuweisung wie "a := 'abc'" sondern AStream.Read kopiert letztendlich zeischen von einer Stelle an eine andere Stelle im Speicher.
Du könntest also
Delphi-Quellcode:
AStream.Read(Pointer(20)^, 50);
schreiben und damit versuchen an die Adresse "20", 50 Bytes aus dem Stream zu kopieren. Als Ergebnis wird dir dann jedoch eine Fehlermeldung wie "Zugriffsverletzung an Adresse 000020" oder so ausgegeben.
AStream.Read erwartet also einfach eine Adresse (dereferenziert) so es Daten hinschreiben kann.

Als Bildlisches Beispiel. Du bestellst eine LKW-Ladung Sand uns sagst dem LKW-Faherer wo er das ganze abladen soll. Der LKW wird dann an die entsprechende stelle gefahren und kippt dort den Sand ab. Dem LKW-Fahrer ist es dabei egal ob er das ganze in einen Sandkasten ablädt der eventuell zu klein ist oder auf das Grundstück deines Nachbarn, er lädt es dort hinn wo du es sagst. Und genau so verhält es sich mit dem "Stream.Read" es lädt die Bytes an die Stelle im Speicher die du angibst. Der Vorteil ist das man bei Stream.Read jeden Variablentyp nutzen kann. Wenn es speziel für bestimmte Datentypen (String, Integer, Byte,...) eine Extra funktion gäbe würde man schnell an die grenzen stoßen da ja auch jemand neue Datentypen definieren will die natürlich auch gelesen werden sollen.

Wie dir eventuell auch schon aufgefallen ist hat der erste Parameter von "Stream.Read" keinen Typ, das heißt innerhalb der Funktion kann man nicht einfach
Delphi-Quellcode:
function TYourStream.Read(var Buffer; Count: Integer): Integer;
begin
  ShowMessage(Buffer);
schreiben weil Buffer kein String ist
und auch
Delphi-Quellcode:
function TYourStream.Read(var Buffer; Count: Integer): Integer;
begin
  ShowMessage(inttostr(Buffer));
geht nicht weil Buffer auch kein Integer ist. Buffer ist undefiniert und wird deshalb einfach als Pointer behandelt.

Folgendes geht jedoch:
Delphi-Quellcode:
function TYourStream.Read(var Buffer; Count: Integer): Integer;
begin
  Integer(Buffer) := 5;
damit würde man durch den Cast dem Compiler mitteilen das buffer als Integer zu behandeln ist. Da es aber nich in jedem fall ein Integer ist kann man sowas nicht schreiben und daher wird das ganze einfach als pointer behandelt. Obiges ist also nix anderes als
Delphi-Quellcode:
function TYourStream.Read(var Buffer; Count: Integer): Integer;
begin
  Pinteger(@Buffer)^:= 5;
Da innerhalb der Funktion ja nicht bekannt ist welcher Typ "Buffer" ist kann somit auch nicht festgestellt werden wie groß der Eventuelle String ist (weil ja nichtmal bekannt ist das es ein String ist) und deshalb musst du vorher den Speicher für den String besorgen (mit SetLength) und dann bei Stream.Read angeben wie groß der verfügbate Speicher ist (der zweite Parameter).

Wenn du in deinem Quelltext an irgend einer Stelle folgendes hast:
Delphi-Quellcode:
function TYourStream.Read(var Buffer; Count: Integer): Integer;
var LString: String;
begin
  LString := '123456';
so weiß der compiler das '123456' 6 Zeischen lang ist und reserviert automatisch den Speicher was im in dem fall mit dem Stream aber nicht möglich ist da ja nicht bekannt ist wieviel zeischen wirklich zugewiesen werden.


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:02 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz