Delphi-PRAXiS
Seite 1 von 4  1 23     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Frage zum Buffer eines Streams (https://www.delphipraxis.net/96564-frage-zum-buffer-eines-streams.html)

alleinherrscher 26. Jul 2007 21:53


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

sirius 26. Jul 2007 22:01

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?

alleinherrscher 26. Jul 2007 22:13

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

sirius 26. Jul 2007 22:18

Re: Frage zum Buffer eines Streams
 
Und was ist deine Zielvariable?

Also für string dürfte es so aussehen:
Delphi-Quellcode:
setlength(s,30);
stream1.read(s[1],10);
stream2.read(s[11],10);
stream3.read(s[21],10);
Ähnlich sieht es für arrays aus.

alleinherrscher 26. Jul 2007 22:26

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?

alleinherrscher 28. Jul 2007 15:45

Re: Frage zum Buffer eines Streams
 
*push* ;)

sirius 28. Jul 2007 16:00

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.

3_of_8 28. Jul 2007 17:13

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;

alleinherrscher 28. Jul 2007 19:35

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: hier

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.

Muetze1 28. Jul 2007 19:50

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:


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:15 Uhr.
Seite 1 von 4  1 23     Letzte »    

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