![]() |
Frage zum Buffer eines Streams
Hi!
Ganz simple Frage diesesmal: Der Read und Write Procedure eines Streams kann man einen Buffer (Void Typ) übergeben, der die Daten enthält, die zu lesen und schreiben sind. Was ist dieser Buffer intern? Ein Array of Byte? Kann ich einen Buffer vordefinierter Länge manuell erzeugen und dann an verschiedenen Stellen des Buffers selber Daten reinschreiben? Also wenn ich z.B. 3 "Buffer" haben...kann ich die irgendwie zu einem Buffer vereinigen? Danke und viele Grüße Euer Alleinherrscher |
Re: Frage zum Buffer eines Streams
Der Buffer ist einfach ein Stück Spiecher, der dir gehört; den du also reserviert hast. Das kann ein array sein, ein string oder einfach nur ein pointer auf ein stück freien Speicher.
Was willst du denn genau machen? |
Re: Frage zum Buffer eines Streams
Stell dir vor, ich hätte z.B. 3 verschiedene MemoryStreams,
meine Prozedur soll jedem Stream ein Stückchen "Buffer" lesen können, und am Schluss die drei aus dem Speicher eingelesenen Teile zusammenfügen. Ich könnte zwar erst aus den drei Streams die jeweiligen Stückchen per Copystream in einen neuen Stream kopieren und dann diesen komplett lesen, aber das erscheint mir etwas doppelt gemoppelt und Speicherauswendig, wenn die Streams groß sind. Grüße |
Re: Frage zum Buffer eines Streams
Und was ist deine Zielvariable?
Also für string dürfte es so aussehen:
Delphi-Quellcode:
Ähnlich sieht es für arrays aus.
setlength(s,30);
stream1.read(s[1],10); stream2.read(s[11],10); stream3.read(s[21],10); |
Re: Frage zum Buffer eines Streams
Meine Zielvariablen sind unterschiedlich. Einmal nen String, dann wieder n Integer, dann Daten die nen ganzes Bild enthalten und so... kann man das irgendwie "allgemein" machen?
|
Re: Frage zum Buffer eines Streams
*push* ;)
|
Re: Frage zum Buffer eines Streams
Du musst nicht nur pushen, sondern deine Frage mal genauer stellen, wenn bisher keiner geantwortet hat :wink:
Ich weis nämlich nicht, was du noch willst. |
Re: Frage zum Buffer eines Streams
Prinzipiell ist ein Buffer ein Stück Speicher, von dem du die Anfangsposition und die Länge weißt. Ein Buffer kann ein Integer sein, ein String, ein Record, ein statisches oder dynamisches Array - kurz, alles, was Speicher braucht.
Wenn du mehrere Variablen hast, geht das so:
Delphi-Quellcode:
var a, b: Integer;
c: String; d: TMyRecord; e: Single; f: array of Integer; g: array[0..2] of Single; s: TStream; begin //... s.Write(a, 4); //oder s.Write(a, sizeof(a)); oder s.Write(a, sizeof(Integer)); s.Write(b, 4); s.Write(c, length(c)); //Aufpassen bei Multibyte-Char-Strings s.Write(d, sizeof(d)); s.Write(e, 4); //oder s.Write(e, sizeof(e)); usw. s.Write(f[0], length(f)*4); //oder s.Write(f[0], length(f)*sizeof(Integer)); s.Write(g[0], length(g)*4); //oder s.Write(g, length(g)*4); oder s.Write(g, length(g)*sizeof(Single)); //... end; |
Re: Frage zum Buffer eines Streams
Liste der Anhänge anzeigen (Anzahl: 1)
Ich kann euch ja mal meinen Quelltext so far zuschicken. Es geht um einen etwas erweiteren Stream. Man soll ihn aus Dateien einlesen können und dann in den Stream schreiben können, ohne dabei die Datei selbst zu ändern oder die gesamte Datei in den Arbeitsspeicher zu laden.
Ich hatte schonmal früher einen Thread dazu gestartet: ![]()
Delphi-Quellcode:
unit BufferedStream;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs; type aPart = ^TPart; TPart = record PositionInStream:integer; Length:integer; FindAtPosition:integer; end; aBuffer=record MemoryStream:TMemoryStream; FileStream:TFilestream; Swaped:Boolean; PartsInfo:array of aPart; end; TBufferedStream = class(TStream) Constructor Create(OpenFromFilename:string;TempDirectory:string); function write(Const Buffer;Count:integer):integer; procedure ManageStreamType; procedure ReadBuffer(var Buffer;Count:integer); procedure WriteBuffer(Const Buffer;Count:integer); function read(var Buffer;Count:integer):integer; private { Private-Deklarationen } aFileStream:TFilestream; Buffer:aBuffer; swapsize:integer; TempFileName:string; TempDirectory:string; procedure SetPos(newpos:int64); procedure setsize(newsize:int64); public gSize:int64; Pos:int64; property Position: int64 read Pos write SetPos; property Size: int64 read gSize write Setsize; { Public-Deklarationen } end; implementation function GetTempFileName(TempDirectory:String):string; var filename:string; i:integer; begin i:=0; filename:=inttostr(i)+'.part'; while fileexists(TempDirectory+filename) do begin inc(i); filename:=inttostr(i)+'.part'; end; result:=TempDirectory+filename; end; procedure TBufferedStream.setsize(newsize:int64); begin gSize:=newsize; end; procedure TBufferedStream.SetPos(newpos:int64); begin pos:=newpos; end; procedure TBufferedStream.ManageStreamType; begin with Buffer do begin if Swaped then begin if FileStream.size<(2/3)*Swapsize then begin MemoryStream:=TMemoryStream.Create; FileStream.Position:=0; MemoryStream.CopyFrom(FileStream,FileStream.size); freeandnil(Filestream); DeleteFile(TempFileName); Swaped:=False; end end else if MemoryStream.size>Swapsize then begin Filestream.Create(TempFileName,fmCreate); MemoryStream.Position:=0; FileStream.CopyFrom(MemoryStream,MemoryStream.size); freeandnil(MemoryStream); Swaped:=True; end; end; end; procedure TBufferedStream.WriteBuffer(Const Buffer;Count:integer); var addsize:integer; begin with self.Buffer do begin SetLength(PartsInfo,Length(PartsInfo)+1); PartsInfo[Length(PartsInfo)-1]:=new(aPart); PartsInfo[Length(PartsInfo)-1].PositionInStream:=Pos; PartsInfo[Length(PartsInfo)-1].Length:=Count; if Swaped then begin FileStream.Position:=FileStream.size; PartsInfo[Length(PartsInfo)-1].FindAtPosition:=Filestream.Position; FileStream.Write(Buffer,count); end else begin if MemoryStream.Size+Count>SwapSize then begin Filestream:=TFilestream.Create(TempFileName,fmCreate); MemoryStream.Position:=0; FileStream.CopyFrom(MemoryStream,MemoryStream.size); freeandnil(MemoryStream); Swaped:=True; FileStream.Position:=FileStream.size; PartsInfo[Length(PartsInfo)-1].FindAtPosition:=Filestream.Position; FileStream.Write(Buffer,count); end else begin MemoryStream.Position:=MemoryStream.Size; PartsInfo[Length(PartsInfo)-1].FindAtPosition:=MemoryStream.Position; MemoryStream.Write(Buffer,Count); end; end; end; addsize:=Count-(gSize-Pos); Pos:=Pos+Count; if addsize>0 then gSize:=gSize+addsize; end; procedure TBufferedStream.ReadBuffer(var Buffer;Count:integer); var i:integer; len:integer; Start:integer; Ende:integer; PartStart:integer; PartEnde:Integer; InvolvedParts:TList; MyPart:aPart; BufferStream:Tmemorystream; offset:integer; ReadStart,ReadEnd:integer; begin //Zunächst alle Parts finden, die ganz oder Teilweise im zu lesenden Streamabschnitt stecken: InvolvedParts:=TList.Create; with self.Buffer do for i:=0 to length(PartsInfo)-1 do begin Start:=Pos; Ende:=Pos+Count; PartStart:=PartsInfo[i].PositionInStream; PartEnde:=PartsInfo[i].PositionInStream+PartsInfo[i].length; if ((PartStart>=Start) and (PartStart<Ende)) or ((PartEnde>=Start) and (PartEnde<Ende)) or ((PartStart<=Start) and (PartEnde>=Ende)) then InvolvedParts.Add(PartsInfo[i]); end; //Jetzt den Stream zusammensetzten BufferStream:=TMemorystream.create; BufferStream.SetSize(count); if self.aFileStream<>nil then begin aFileStream.Position:=Pos; BufferStream.copyfrom(aFilestream,count); end; while InvolvedParts.count>0 do begin MyPart:=InvolvedParts.First; PartStart:=MyPart.PositionInStream; PartEnde:=PartStart+MyPart.Length; If Start<PartStart then ReadStart:=PartStart else ReadStart:=Start; If Ende<PartEnde then ReadEnd:=Ende else ReadEnd:=PartEnde; len:= ReadEnd-ReadStart; Bufferstream.position:= Start-ReadStart; offset:=PartStart-ReadStart; if offset>0 then offset:=0; if self.Buffer.swaped then begin self.Buffer.FileStream.position:=MyPart.FindAtPosition-offset; BufferStream.CopyFrom(Self.Buffer.FileStream,len); end else begin self.Buffer.MemoryStream.position:=MyPart.FindAtPosition-offset; BufferStream.CopyFrom(Self.Buffer.MemoryStream,len); end; InvolvedParts.Delete(InvolvedParts.IndexOf(MyPart)); end; Pos:=Pos+count; BufferStream.Position:=0; BufferStream.Read(Buffer,count); freeandnil(BufferStream); end; function TBufferedStream.read(var Buffer;Count:integer):integer; begin readbuffer(Buffer,count); end; function TBufferedStream.write(Const Buffer;Count:integer):integer; begin WriteBuffer(Buffer,Count); end; Constructor TBufferedStream.Create(OpenFromFilename:string;TempDirectory:string); var i: integer; begin Self.TempDirectory:=TempDirectory; SwapSize:=5*1024; Pos:=0; gSize:=0; TempFileName:=GetTempFileName(TempDirectory); aFileStream:=Nil; if OpenFromFileName<>'' then begin aFileStream:=TFilestream.Create(OpenFromFileName,fmOpenRead); gSize:=aFilestream.Size; aFilestream.Position:=0; end; with Buffer do begin MemoryStream:=TMemoryStream.Create; Swaped:=False; SetLength(PartsInfo,0); end; end; end. |
Re: Frage zum Buffer eines Streams
Aber wäre dafür nicht eine Kapselung von Memory Mapped Files (MMF) besser geeignet? Vor allem weniger Aufwand und dabei Erfüllung aller deiner Anforderungen... :gruebel:
|
Re: Frage zum Buffer eines Streams
Mit MemoryMappedFiles kenne ich mich gar nicht aus. Aber ich hab mal ein bisschen gesucht. Irgendjemand meinte hier im Forum mal, dass die eigentlich für andere zwecke eingesetzt werden sollen.
Unterdessen habe ich mal ein bisschen weiterprogrammiert. Das schreiben in meinen BufferedStream und das Lesen funktionieren jetzt eigentlich ganz gut. Ich füge keine Buffer zusammen (wonach ich ursprünglich oben gefragt hatte, sondern ich nehme noch einen zusätzlichen Hilfstream, in den ich alle Speicherteile einfüge und den ich dann am schluss einmal komplett auslese -> dieser Buffer wird dann als result übergeben. (hm schwer zu beschreiben) Allerdings bekomme ich richtig probleme, wenn ich versuch über die Stream.CopyFrom Funktion Daten aus meinem BufferedStream in einen anderen, z.B: MemoryStream zu kopieren. Dann kommt eine Böse Speicherzugriffsverletzung. Weiß jemand, welche Prozeduren von TStream aufgerufen werden, wenn man die TStream.CopyFrom(BufferedStream,0) Prozedur aufruft? Desweiteren habe ich etwas eigenartiges in der Delphi Hilfe gelesen: Zitat:
Grüße, und vielen Dank für eure Antworten, Alleinherrscher |
Re: Frage zum Buffer eines Streams
1. TStream ist insofern eine abstrakte Klasse, als dass die wichtigsten Methoden (auf die auch alle anderen mit zugreifen) abstrakt deklariert sind. Ausserdem legt TStream sich noch nicht auf einen Speicherplatz fest (hat also keine Variable o.ä. wo es irgendetwas speichern könnte). Das bedeutet, erst wenn man dem TStream sagt, dass es als Memorystream arbeiten soll, gibt es da eine Pointervariable, die auf den Speicherplatz zeigt und ausgefüllte read und write Methoden, die dort Speichern können. Ähnliches gilt für TFilestream. Also, erst wenn TStream zum Filestream wird, erhält die Sache zum speichern eine Datei und die entsprechenden read und write Methoden.
Dagegen sind andere Methoden, wie Readbuffer und Writebuffer, ReadComponent, etc. pp. schon in TStream vollständig implementiert. Sie benutzen eben immer read und write und ihnen ist dann völlig egal, ob dahinter ein FileHandle oder ein "Memory"-Pointer, oder ein String (TStringStream) liegt. Neben read und write ist noch SetSize und Seek abstrakt. Wenn du von TStream ableitest, musst du alle abstrakten Methoden überschreiben (override) und kannst dir eben bei Read und Write deinen eigenen Speichertyp aussuchen. Das ist ja so in etwas das, was du auch willst. Du hast es nur verkehrtherum gemacht. Du musst nicht readbuffer und writebuffer überschreiben, sondern nur read und write. 2. CopyFrom ruft readbuffer und writebuffer auf. Du kannst doch auch im Source nachschauen. Edit: :pale: Du kannst doch nicht im Source nachschauen. Hol dir doch mal Turbo Delphi... Edit2: Achtung beim überschreiben von setsize und seek. Die Methoden sind überladen. |
Re: Frage zum Buffer eines Streams
Danke, sirius, ich hoffe jetzt komme ich erstmal weiter... ich werd mal versuchen deine tipps umzusetzten und mich dann nochmal melden!
Muss ich also alle überladenen Methoden überschreiben? wie sieht da die deklaration aus? |
Re: Frage zum Buffer eines Streams
Delphi-Quellcode:
procedure/function <Name und Parameter>; override;
|
Re: Frage zum Buffer eines Streams
Ich habe nochmal (genauer) nachgeschaut.
Nee, nicht alle überladenen Methoden. Die int64 Varianten prüfen !derzeit! nur ob der Bereich innerhalb von longint ist und rufen dann die LongInt varianten auf (ansonsten gibts ne Exception). ==> Es reichen die LongInt Varianten. Übrigens: SetSize und Seek sind zwar nicht abstrakt, sie haben nur keinen wirklichen Inhalt. Also SetSize(Longint) ist tatsächlich leer und seek überprüft nur ob es eine neue Implementation von Seek gibt. Wenn nicht wird ne Exceptuion geworfen...hätte man es da nicht gleich abstrakt machen können :gruebel: (Alle Auskünfte ... so weit ich den Code verstanden habe) |
Re: Frage zum Buffer eines Streams
Liste der Anhänge anzeigen (Anzahl: 1)
Hm, ich hab es jetzt mal so umprogrammiert (ich hänge die entsprechende Unit mal an, ich glaub das ist besser als die hier einzukopieren.
Allerdings bleibt die Zugriffsverletzung (wenn ich z.B TMemoryStream.CopyFrom(TBufferedStream,0) ) teste. Kannst du evtl. mal meine Deklarationen checken, sirius? Ich hab leider nicht so viel Ahnung von Klassenableitungen und überladen von Funktionen? Bekommst auch ein Eis von mir ausgegeben, wenn das wetter besser ist und du mal in meiner Nähe bist :D Tausend Dank!!!!!!!!!!!!!!!! //edit: Jetzt sagt nicht, ich muss die Read Function auch überladen?!?!?! In der Borland Hilfe stehen ungefähr 15 überladene Funkionen davon... :wall: |
Re: Frage zum Buffer eines Streams
Hmm..ich weis nicht, was du mit den ganzen parts so machst.
Bevor ich da durchsehe und das auseinanderbaue, habe ich mal versucht, deine Absicht in einer anderen Klasse niederzuschreiben. (Allein, der Sinn fehlt mir noch, aber egal)
Delphi-Quellcode:
Jetzt ist mir auch übrigens klar, was deine Eingangsfrage war. Wenn der Buffer untypisiert ist, dann musst du eben auch ganz untypisiert rangehen:
unit Unit2;
interface uses classes; type tBufferStream=class(TStream) constructor create(const OpenFromFileName:string;TempDirectory:string); reintroduce; destructor Destroy; override; private FMemory:TStream; TempDir,TempFile:string; swapsize:integer; protected procedure SetSize(NewSize: Longint); override; public function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(Offset: Longint; Origin: Word): Longint; override; end; implementation uses sysutils; function GetTempFileName(TempDirectory:String):string; var filename:string; i:integer; begin i:=0; filename:=inttostr(i)+'.part'; while fileexists(TempDirectory+filename) do begin inc(i); filename:=inttostr(i)+'.part'; end; result:=TempDirectory+filename; end; constructor TBufferStream.create(const OpenFromFileName:string;TempDirectory:string); var f:Tfilestream; begin TempDir:=TempDirectory; swapsize:=5*1024; if openfromfilename<>'' then begin f:=Tfilestream.Create(OpenFromFileName,fmopenread); if f.size>swapsize then FMemory:=TFilestream.Create(gettempfilename(tempdir),fmcreate) else Fmemory:=TMemoryStream.Create; Fmemory.CopyFrom(f,f.size); f.free; end else Fmemory:=nil; end; function Tbufferstream.Write(const Buffer;Count: Longint): Longint; var tmp:TStream; begin if Fmemory=nil then Fmemory:=Tmemorystream.Create; if (Fmemory is TMemoryStream) and (Fmemory.Size+count>swapsize) then begin tempfile:=gettempfilename(tempdir); tmp:=TfileStream.Create(tempfile,fmcreate); Fmemory.Seek(0,sofrombeginning); tmp.CopyFrom(Fmemory,fmemory.size); Fmemory.Free; FMemory:=tmp; end; result:=Fmemory.Write(buffer,count) end; function TBufferStream.read(var Buffer;Count: Longint): Longint; begin result:=FMemory.Read(buffer,count); end; function TbufferStream.Seek(Offset: Longint; Origin: Word): Longint; begin result:=Fmemory.Seek(offset,origin); end; procedure Tbufferstream.SetSize(Newsize:longint); var tmp:TStream; begin if FMemory=nil then Fmemory:=Tmemorystream.Create; Fmemory.Size:=newsize; if (newsize<swapsize*2/3) and (Fmemory is TFilestream) then begin tmp:=Tmemorystream.Create; Fmemory.Seek(0,sofrombeginning); tmp.CopyFrom(FMemory,newsize); fmemory.Free; fmemory:=tmp; deletefile(tempfile); end; if (newsize>swapsize) and (Fmemory is TMemorystream) then begin tempfile:=gettempfilename(tempdir); tmp:=TFilestream.Create(tempfile,fmcreate); Fmemory.Seek(0,sofrombeginning); tmp.CopyFrom(FMemory,newsize); fmemory.Free; fmemory:=tmp; end; end; destructor TbufferStream.Destroy; begin if Fmemory<>nil then begin if FMemory is TFileStream then begin Fmemory.Free; deletefile(TempFile); end else Fmemory.Free; end; end; end.
Delphi-Quellcode:
var buffer:pointer;
begin GetMem(Buffer,10); Stream.ReadBuffer(Buffer^,10); //... FreeMem(Buffer,10); end; |
Re: Frage zum Buffer eines Streams
DANKE!!!
Ich werds direkt probieren!!!!! Mensch, wenn das klappt, das wäre richtig toll... Wenn du magst schreib ich dir nochmal was zu dem "Sinn und Zweck", jedenfalls so wie ich mir das gedacht habe. Aber ich versuche erstmal weiterzukommen ;) Lg, Alleinherrscher //edit: Du kopierst am Anfang die Daten einmal in einen neuen Stream! Im grunde eine gute Idee, aber was passiert, wenn die Datei, die in den Stream soll, richtig groß, z.B. 1GB ist? dann muss er doch den gesamten 1GB File praktisch komplett kopieren oder? Genau das gilt es ja zu verhindern um schneller arbeiten zu können...aber ich werde es einfach mal testen, vielleicht ists so ja auch schnell! edit2: ich habe mal schnell eine kleine Grafik gemacht, was ich überhaupt genau will... ![]() Vielen vielen Dank für die ganze Mühe!!! |
Re: Frage zum Buffer eines Streams
Ahhh, ok.
Sehr interessante Komponente. die Aufgabe erfüllt meine allerdings nicht. Ich hatte dem aFileStream nicht so ein große Beachtung geschenkt, wie es notwendig wäre. Was wäre, wenn du in den MemoryStream auch gleich die Positionen mit speichern würdest? Edit: Es haben sich grad so ziemlich alle Fragen meinerseits bezüglich deines Codes geklärt. :wink: Aber einiges musst du noch ändern. CopyFrom liefert z.B. Fehler, wenn du über das Ende des Streams hinausliest:
Delphi-Quellcode:
Hier ist (so weit ich sehe) nicht sichergestellt, dass Pos+Count < aFileStream.size.
aFileStream.Position:=Pos;
BufferStream.copyfrom(aFilestream,count); Und bei mir siehst du wofür abstrakte Methoden nützlich sind. Ich brauche nicht ein Memorystream und einen Filestream extra. ich habe einfach nur einen Stream und trotzdem kann ich die Methoden read und write benutzen, da ich den Stream mit TMemorystream oder eben TFilestream erzeuge. Und ich bruache auch keine Variable swapped, da ich meine Stream-Variable abfragen kann, was sie gerade ist. |
Re: Frage zum Buffer eines Streams
Genau das hatte ich auch zuerst vor, aber macht die sache nicht wesentlich einfacher oder? *grübel* naja, ich versuche jetzt mal, in deine struktur meine Idee mit dem zusätzlichen stream einzubauen... hoffe es klappt irgendwie...
|
Re: Frage zum Buffer eines Streams
Zitat:
Edit: Wer ruft den die Read-Methode auf? Wahrscheinlich wäre es noch sinnvoll eine savetoFile etc. Methode zu implementieren. |
Re: Frage zum Buffer eines Streams
@sirius:
Hm allerdings ist meins etwas unverständlich oder? Blickst du da durch? zu deinem edit: beides wäre brauchbar: ein Read und ein SavetoFile. Aber wenn du das Read hast, ist das Savetofile doch vom selben Prinzip oder? Und jap du hast recht, die Abstrakte Lösung ist wirklich knackig kurz und besser :) //edit: die READ methode brauche ich später im "externen Programm"...oder wie meinst du die frage? |
Re: Frage zum Buffer eines Streams
Ich würde das in mehreren Schritten angehen:
1. Speichern der Änderungen in einer separaten Struktur:
Delphi-Quellcode:
Wenn man einen weiteren Wert der Größe N an Stelle P speichert, und es existiert ein 'Saved Item' S an der Position P-N, dann kann man S erweitern (siPos += N). Existiert ein saved Item an der Stelle S.siPos = P+N, dann kann man S wieder erweitern (siPos -= N, siSize += N).
TSavedItem = Record
siPos, siSize : Cardinal; siData : Pointer; End; 2. Sicherstellen, das bei einem READ auf dem Stream die unveränderten und veränderten (Saved Item Liste) korrekt zurückgeliefert werden. 3. Speichern der Saved Item Liste in einem Stream, allerdings würde ich hier die Liste im Speicher, und nur die siData-Teile auslagern. Dies dürfte sehr komplex werden, wenn es optimal performant werden soll. Eigentlich handelt es sich um einen Stream, der mit Transaktionen arbeitet. Es gibt so eine Komponente schon, ich meine, ich hätte sie bei Torry gesehen... |
Re: Frage zum Buffer eines Streams
Zitat:
Achja und: Zitat:
|
Re: Frage zum Buffer eines Streams
Zitat:
Zitat:
Zitat:
Also, wie in einen Buffer schreiben?
Delphi-Quellcode:
procedure xyz.read(var buffer);
var buf:pointer; begin buf:=@buffer; filestream.read(buf^,10); buf:=pointer(cardinal(buf)+10); filestream.seek(100,sofromcurrent); filestream.read(buf^,3); buf:=pointer(cardinal(buf)+3); ... end; |
Re: Frage zum Buffer eines Streams
Liste der Anhänge anzeigen (Anzahl: 1)
Hey@all und Hi Sirius!
Ich hab die Änderungen mal eingebaut. Muss sagen, bis jetzt haben alle meine Tests funktioniert. Wenn du magst, kannst du (natürlich auch gerne alle anderen) mal testen, obs noch Bugs gibt. Falls dies okay ist, fehlen natürlich noch eine optimierte Version von SaveToFile. Wie würdet ihr die angehen, ohne Read und CopyFrom zu benutzten...und ohne die Performence zu zerstören? Grüße Alleinherrscher //edit: noch einen Fehler entdeckt, bei CopyFrom wenn man eine Datei als Filestream eingeladen hat, verändert, dann den gesamtem Stream kopiert sind die änderungen weg...ich werd mich mal dranbegeben... |
Re: Frage zum Buffer eines Streams
1. Den Filestream musst du noch im Destructor freigeben
2. Die (meine) Funktion setsize funktioniert so nicht mehr. Besonders in dem Fall, wenn die Größe verkleinert wird. Denn dann kannst du ja Teile aus dem FStream löschen bzw. den Filestream kürzen. 3. Wolltest du nicht kleine Dateien statt in den FileStream erstmal in FStream laden? 4. in seek musst du evtl noch mySize anpassen (Wenn myPosition>mysize) Zu edit (Denk daran, dass du auch bei der Anwendung von copyFrom Fehler machen kannst (ich vergesse meistens die Position zu verändern) zu2:
Delphi-Quellcode:
procedure TBufferstream.SetSize(Newsize:longint);
begin if Newsize<mysize then begin //Speicher freigeben (ist allerdings nicht notwendig) if Filestream.size<newsize then Filestream.size:=newsize; //evtl, oder du lässt die Datei bestehen //und hier jetzt für jeden Part in FStream, schauen ob er gekürzt werden kann end; mysize:=newsize; end; |
Re: Frage zum Buffer eines Streams
Okay, das werde ich sofort ändern, danke!
//edit zu deinem Punkt drei: Ja, aber ich glaube so ist es einfacher, weil wir nicht noch zusätzlich die Fälle unterscheiden müssen , ob der Stream jetzt "bearbeitet werden darf" oder nicht... arg: Deutsche Sprache ist zu beschränkt ;) Noch ne grundsätzliche verständnisfrage zu den Pointern (die Deklaration vom Buffer): Ich lese ja im Augenblick in der READ function erst den Filestream mit Filestream.read(buf^,count); Will ich jetzt an einer bestimmten Position ein Datenpacket aus dem MemoryStream einsetzten, wie geht das? Ich hab es ja im Augenblick so gelöst:
Delphi-Quellcode:
Aber scheinbar funktioniert dies nicht sauber?!BufStart:=cardinal(buf); if FileStream<>nil then begin FileStream.Seek(MyPosition,soFromBeginning); NumberOfReadByte:=Filestream.Read(buf^,count); end; //und dann um das Paket irgendwie in die Mitte vom Buffer zu setzen: buf:=pointer(BufStart+(Start-ReadStart)); //... FMemory.position:=MyPart.FindAtPosition-offset; FMemory.Read(buf^,len); Grüße |
Re: Frage zum Buffer eines Streams
Oh ja, da scheint mir noch folgende Zeile zu fehlen:
Delphi-Quellcode:
Und an der Zeile ist auch noch was komsich:
if FileStream<>nil then
begin FileStream.Seek(MyPosition,soFromBeginning); NumberOfReadByte:=Filestream.Read(buf^,count); buf:=pointer(cardinal(buf)+NumberOfReadByte); //<--- die hier end;
Delphi-Quellcode:
Was ist wenn ein Block aus FMemory über die Länge von Filestream hinausgeht?
result:=NumberOfReadByte
Was ist wenn von außen die erwartete Größe (=mySize) ungleich NumberOfReadByte ist? (Dann gibt übrigens copyfrom irgendsoein EReadError.) |
Re: Frage zum Buffer eines Streams
OMG, ja das is ja ein Dummer Fehler, ich war bis jetzt immer davon ausgegangen, dass mein Filestream länger ist, als alles andere... Aber man kann ja auch daten HINTER den Filestream schreiben...dummdummdumm... sorry! :wall:
Aber wenn ichs so mache, wie du oben getextet hast:
Delphi-Quellcode:
Dann würden doch bei einem weiteren Read vorgang die Daten an das ENDE von Buffer weitergeschrieben, richtig? Gibt es keine Möglichkeit (so ähnlich wie beim Stream selbst), mitten in den Buffer nochmal was reinzuschreiben bzw einlesen zu lassen?
if FileStream<>nil then
begin FileStream.Seek(MyPosition,soFromBeginning); NumberOfReadByte:=Filestream.Read(buf^,count); buf:=pointer(cardinal(buf)+NumberOfReadByte); //<--- die hier end; Ach, sonst muss ich es eben etwas umschreiben...ich schau mal, danke erstmal! Das is noch ne Menge Arbeit, merke ich grade... |
Re: Frage zum Buffer eines Streams
Zitat:
Dann ist die Zeile natürlich Quark. Dann dürfte doch alles funktionieren (wenn die Rechnung mit Start und ReadStart stimmt). Du kannst problemlos überschreiben. Buf (bzw. buffer) zeigen doch nur auf ein Stück Hauptspeicher. Und dort schreibst du rein ohne dich für den Inhalt oder für die Speicherreservierung zu kümmern. Der Inhalt ist dir eh wurscht und die Speicherreserveirung muss bei allen Streams die aufrufende Funktion machen. |
Re: Frage zum Buffer eines Streams
Liste der Anhänge anzeigen (Anzahl: 1)
Okay, fehler in der Positionsberechnung von ReadStart behoben. Also bei mir läufts jetzt ganz gut...
SaveToFile ist allerdings noch buggy... //edit: wieder ein paar Fehler bzgl. Setsize gefunden... |
Re: Frage zum Buffer eines Streams
Die Klasse TBufferStream sollte so konstruiert sein, dass man ein beliebiges TStream-Objekt übergibt (anstelle eine Dateinamen).
Wie man's richtig macht kann man z.B. in der Unit JclStreams der ![]() |
Re: Frage zum Buffer eines Streams
Erstmal muss ich sagen: Echt nette Komponente. :thumb:
Ein paar Sachen fallen mir auf: Wieso swapt ihr eigentlich selber FMemory auf die Platte? Kann man das nicht auch Windows überlassen? Ich meine, das Windows das bessere Memory management hat, oder irre ich mich? Ich halte das auch für eine Performancebremse, denn entweder habt ihr ALLES im RAM, oder ALLES auf der Platte... Ich hab den Code nur überflogen, aber mir fällt da eine kleine Schwachstelle auf: Wenn ich mehrmals an die gleiche Stelle etwas schreibe, dann hängt ihr trotzdem immer einen 'aPart' an die PartsInfo-Liste an. Das ist überflüssig. Das ist mit der (zugegebenermaßen ziemlich einfach wie genialen) Methode mit dem einen FMemory - Stream nicht optimal lösbar. Wenn man jedoch davon ausgeht, das in dem Stream nicht sonderlich viel überschrieben wird, ist das nicht so wild. Die Routine GetTempName ist blöd, nehmt lieber die WinAPI-Version
Delphi-Quellcode:
In der SaveToFile-Methode steckt ein Denkfehler:
Function TempPath: String;
Var i: integer; Begin SetLength(Result, MAX_PATH); i := GetTempPath(Length(Result), PChar(Result)); SetLength(Result, i); IncludeTrailingPathDelimiter(Result); End; Function TempFilename: String; Begin SetLength(Result, MAX_PATH + 1); GetTempFileName(PChar(TempPath), 'CSI', 0, PChar(result)); End;
Delphi-Quellcode:
Also: Ich schreibe an Pos:1 und Pos:100 jeweils ein Byte (z.B. A und B). Dann steht in PartsInfo (Pos:1, Size:1, FindAtPosition:0) sowie (Pos:100, Size:1, FindAtPosition:1) und der FMemory-Stream enthält 'AB'. Das ist aber nicht der fertige Stream, oder irre ich mich?
...
if i>=PartsInfo.Count-1 then //alle Elemente in FMemory sind Sortiert hinterheinander if (FMemory is TMemoryStream) then // => FMemory ist bereits fertiger Stream! DENKFEHLER!!! TMemoryStream(FMemory).SaveToFile(Filename) ... Ihr könntet die einzelnen Parts aus Partinfo jeweils mit
Delphi-Quellcode:
in den Ziel-Stream schreiben
FMemory.Seek (FindAtPositon, soFromBeginning);
stDestStream.Seek (PositionInStream, soFromBeginning); stDestStream.CopyFrom (FMemory, Length); Na ja, und dann wären da noch ein paar kosmetische Kleinigkeiten: aPart ist ein *schlechter* Bezeichner für einen Datentypen. Auch würde ich daraus eine Klasse machen. Ansonsten: Echt Cool. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:40 Uhr. |
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