Entwickler-Ecke
Sonstiges (Delphi) - TStream aufteilen
Dolognio - Fr 03.11.06 11:26
Titel: TStream aufteilen
Hi @ all.
Ich habe
hier im Forum [
http://www.delphi-forum.de/viewtopic.php?t=46409] gelesen wie ich in einen Stream ein Identifikationsmerkmal schreiben kann, um zu erkennen, was für ein Datentyp sich in dem Stream befindet. Das klappt auch ohne Compilerfehler.
Meine Frage ist jetzt allerdings: Wie kann ich den Stream nach Empfang wieder so aufteilen, dass erst der erste Teil ausgelesen wird mit dem Merkmal, und dann der Rest dem Datentyp entsprechend? Ich kann mir da absolut nichts drunter vorstelln.
Thx schonmal.
Udontknow - Fr 03.11.06 11:58
Hallo!
Du musst nicht aufteilen. Du ermittelst mit einem Aufruf von
Delphi-Quelltext
1:
| Stream.ReadBuffer(ID,SizeOf(ID)); |
das Identifikationsmerkmal. Anschliessend reagierst du.
Delphi-Quelltext
1: 2: 3: 4:
| if ID=ID_JPG then Picture.LoadFromStream(Stream); if ID=ID_Text then Memo.Lines.LoadFromStream(Stream); |
Erst wenn du "hinter" den JPG-Daten auch noch andere Blöcke sendest, wird es schwieriger. Dann musst du einen temporären Stream hinzunehmen und zusätzlich in den Originalstream auch noch die Größe des Blocks schreiben, damit die Blöcke auseinanderzuhalten sind.
Cu,
Udontknow
Dolognio - Fr 03.11.06 16:17
OK, thx, ich probier des mal so. Mla schauen ob ich des hinkrieg^^.
Cya.
PS: Thread lass ich für evtl weitere Fragen zum Thema ma noch offen bzw. unmarkiert.
Dolognio - Fr 03.11.06 18:11
Hmm, also funzt doch noch nicht wie gewünscht, ka was jetzt wieder los ist. Erst ma der Code:
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:
| const ID_String = 0; const ID_Stringlist = 1;
procedure Testsenden; var sl: TStringlist; stream1, stream2: TMemoryStream; ID: integer; begin sl:= TStringlist.Create; Stream2:= TMemoryStream.Create; sl.Sorted:= false; sl.Clear; sl.BeginUpdate; try sl.add('string1'); sl.add('string2'); sl.add('string3'); sl.add('string4'); sl.add('string5'); sl.add('string6'); sl.add('string7'); sl.add('string8'); sl.EndUpdate; sl.SaveToStream(stream2);
stream1:= TMemoryStream.Create; try ID:=ID_Stringlist; Stream1.WriteBuffer(ID,SizeOf(ID)); try stream1.CopyFrom(stream2,stream2.Size) finally stream2.Free; MainFrm.TCPClient.SendStream(stream1); end; finally stream1.Free; end; finally sl.Free; end; end; |
Ich dachte egtl ich hab alles richtig gemacht, find kein Fehler, außer mn muss im Zusammenhang mit einer Stringliste noch was andres beachten beim Speichern in Stream. Jedenfalls bringt der Debugger zur Laufzeit den Fehler "Stream read error!" in der oben markierten Zeile.
Hoffentlich weißt du noch weiter :( :?:
Narses - Fr 03.11.06 18:25
Moin!
Du mußt Stream2 auch wieder "zurückspulen". ;) So: Stream2.Position := 0;
cu
Narses
Martok - Fr 03.11.06 18:31
Oder statt
Stream2.Size 0 angeben:
Delphi-Quelltext
32:
| { ... } stream1.CopyFrom(stream2,0); |
Dolognio - Fr 03.11.06 23:38
Danke, jetzt klappts endlich, hätt ich in der Delphi-Hilfe geschaut über stream.copyfrom(), hätt ich gewusst dass ich ne 0 einfügen muss^^.
Wenn ich jetzt allerdings 2 verschiedene Merkmale in einen Stream einbauen muss, gilt dann das, was UDontKnow vorhin ma gesagt hat?
Udontknow hat folgendes geschrieben: |
Erst wenn du "hinter" den JPG-Daten auch noch andere Blöcke sendest, wird es schwieriger. Dann musst du einen temporären Stream hinzunehmen und zusätzlich in den Originalstream auch noch die Größe des Blocks schreiben, damit die Blöcke auseinanderzuhalten sind.
|
Und wenn ja, wie sieht dass denn dann aus? Was für Blöcke??? Und temporärer Stream ist TMemoryStream oder?
Udontknow - Sa 04.11.06 21:59
Hier die grobe Vorgehensweise. Ich gehe davon aus, daß jeder "Block" eine ID und eine Size mitgibt. Für jeden Block wird dann ein Stream bereitgestellt und die Funktion VerarbeiteBlock aufgerufen
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:
| procedure VerarbeiteBlock(ID:Integer; Size:Integer; Stream:TStream); begin end;
procedure VerarbeiteBloecke(Stream:TStream); var ID:Integer; var Size:Integer; var TempStream:TMemoryStream; begin While Stream.Position<Stream.Size do begin Stream.ReadBuffer(ID,SizeOf(ID)); Stream.ReadBuffer(Size,SizeOf(Size));
TempStream:=TMemoryStream.Create; try TempStream.Size:=Size; TempStream.CopyFrom(Stream,Size); TempStream.Position:=0; VerarbeiteBlock(ID,Size,TempStream); finally TempStream.Free; end; end; end; |
Cu,
Udontknow
Dolognio - Sa 04.11.06 23:38
Also sry, aber ich werd aus deinem Code nich schlau.
Was versteht man denn überhaupt unter einem "Block"?
Und ich denk ma dass deine beiden Prozeduren zum lesen des gesendeten Streams da sind.
Wie aber speicher ich einen solchen Stream ab?
Einfach
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:
| var sl: TStringlist; TempStream1, TempStream2, SLstream: TMemoryStream; ID: integer; begin sl:= TStringlist.Create; SLstream:= TMemoryStream.Create; try sl.SaveToStream(SLstream);
TempStream2:= TMemoryStream.Create; try ID:= ID_Stringlist; Stream1.WriteBuffer(ID,SizeOf(ID)); try TempStream2.CopyFrom(SLstream,0); TempStream1:= TMemoryStream.Create; try TempStream1.CopyFrom(TempStream2,0); finally SLStream.Free;
finally TempStream2.Free;
end; finally MainFrm.TCPClient.SendStream(TempStream1); TempStream1.Free; end; finally sl.Free; end;
end; |
?? Oder wie sonst?
Und wie gibt man einem "Block" (was auch immer das jetzt ist) ID und Size mit?
Udontknow - So 05.11.06 17:33
Nun, ein Block ist für mich eben ein Paket zusammenhängender Daten.
Beispiel:
Du hast ein Chatprogramm geschrieben, über das du mal Text, mal aber auch ein Bild senden kannst. Nun tritt es ab und zu auf, daß Pakete aneinanderhängen, diese müssen also von dir auseinandergehalten werden. Das erreichst du, indem du die Struktur eben wie beschrieben aufbaust. Immer wenn der User ein Bild senden will, werden zuerst das Merkmal für "Bild", dann die Anzahl der Bytes für das Bild und anschliessend die Daten des Bildes gesendet. Die Empfangsroutine kann anhand des Headers (ID und Groesse) eben erkennen, wo ein Block endet und der nächste beginnt.
Cu,
Udontknow
Dolognio - Mo 06.11.06 00:30
Hmm, also mit Streams muss ich mich glaub erst ma richtig befassen. Hab da noch nich so den Durchblick.
Hab mir daher jetzt auch was andres überlegt, wie ich 2 Merkmale in einen Stream schreiben kann.
Hier der Code:
Sender:
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:
| procedure Testsenden; var sl: TStringlist; stream1, stream2: TMemoryStream; ID: integer; begin sl:= TStringlist.Create; Stream2:= TMemoryStream.Create; sl.Sorted:= false; sl.Clear; sl.BeginUpdate; try
sl.EndUpdate; sl.SaveToStream(stream2);
stream1:= TMemoryStream.Create; try ID:= 15;
Stream1.WriteBuffer(ID,SizeOf(ID)); try stream1.CopyFrom(stream2,0) finally stream2.Free; MainFrm.TCPClient.SendStream(stream1); end; finally stream1.Free; end; finally sl.Free; end; end; |
und
Empfänger:
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:
| const ID_StringList = '1'; const ID_String = '2';
const ID_Frame1 = '1'; const ID_Frame2 = '2'; const ID_Frame3 = '3'; const ID_Frame4 = '4'; const ID_Frame5 = '5';
procedure TForm1.TCPServerInput(Connection: TSimpleTCPConnection; Stream: TStream; var DisposeStream: Boolean); var sl: TStringList; TypID, FrameID: char; ID: integer; h: string; begin stream.ReadBuffer(ID,sizeof(ID)); h:= inttostr(ID); TypID:= h[1]; FrameID:= h[2];
if TypID = ID_StringList then begin sl:= TStringList.Create; try sl.LoadFromStream(stream); if FrameID = ID_Frame5 then Frame5.ListBox1.Items.Assign(sl); finally sl.Free; end; end; end; |
Ist vielleicht nicht so sauber, aber funktioniert. Trotzdem DANKE für eure Geduld mir das alles näherzubringen!! :wink: :lol:
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 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!