Einzelnen Beitrag anzeigen

Benutzerbild von alleinherrscher
alleinherrscher

Registriert seit: 8. Jul 2004
Ort: Aachen
797 Beiträge
 
Delphi XE2 Professional
 
#9

Re: Frage zum Buffer eines Streams

  Alt 28. Jul 2007, 19:35
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.
Angehängte Dateien
Dateityp: rar bufferedstream_713.rar (183,6 KB, 10x aufgerufen)
„Software wird schneller langsamer als Hardware schneller wird. “ (Niklaus Wirth, 1995)

Mein Netzwerktool: Lan.FS
  Mit Zitat antworten Zitat