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 Ableitung, mit Eigenschaften von File- und Memstream? (https://www.delphipraxis.net/96148-stream-ableitung-mit-eigenschaften-von-file-und-memstream.html)

alleinherrscher 19. Jul 2007 13:03


Stream Ableitung, mit Eigenschaften von File- und Memstream?
 
Hi, ich bin auf der suche nach einer Art intelligentem Stream, der von TStream abgeleitet ist, und zunächst die selben eigenschaften hat wie ein Memorystream. Wird aber eine bestimmte Größe im Speicher erreicht, soll er die Daten praktisch auslagern und dann so funktionieren wie ein Filestream. (es wird eine temporäre Datei erstellt).
Warum ich nicht direkt einen Filestream benutzte? Ich bräuchte eine Art filestream, in den man per Write(Buffer, count) daten schreiben kann, ohne die Originaldatei zu verändern. Nun könnte man auf die Idee kommen, einfach eine Kopie der Originaldatei anzulegen. Aber das kann bei großen Dateien ja schonmal ewig dauern und viel Zeit kosten.

Dafür habe ich hier mal ein bisschen was rumexperimentiert, ist alles noch was unschön programmiert, sind erst erste versuche: Ist mein Stream kleiner als 5mb, wird er im speicher gehalten. Danach wird eine temporäre Datei (0.part 1.part usw) erzeugt, in welche die Daten geschrieben werden und dann per Filestream benutzt werden.
Wird ein Stream aus einer vorhandenen Datei geladen, so ist sie "protected". D.h. schreibt man per write neue Daten in den Stream, werden nur die änderungen in einem seperaten Stream gespeichert (ChangeSave).

Ich hab den Code mal angehängt. Vielleicht kann mir jemand ein paar Tipps geben, wie das ganze etwas "schöner" zu programmieren ist. Konkret hänge ich bei dem "read" befehl. Ich versuche grade aus dem ChangeSave (also den gemachten Änderungen) und dem Originalfilestream wieder den gewünschten Stream zusammen zu bauen.

Also bitte nicht hauen, weils unsauber geschrieben ist...

Delphi-Quellcode:

unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;


  type
   TExtendedStream = class(TStream)
     Constructor Create(OpenFromFilename:string);
     function   write(Const Buffer;Count:integer):integer;
     function   read(var Buffer;Count:integer):integer;
  private
    { Private-Deklarationen }
    aStream:TStream;
    ChangeSave:TExtendedStream;
    protect:boolean;
    inMemory:boolean;
    swapsize:integer;
  public
    Size:int64;
        Position:int64;
    { 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;

function GetFileSize(szFile: PChar): Int64;
var
  fFile            : THandle;
  wfd              : TWIN32FINDDATA;
begin
  result := 0;
  if not FileExists(szFile) then exit;
  fFile := FindFirstfile(pchar(szFile), wfd);
  if fFile = INVALID_HANDLE_VALUE then exit;
  result := (wfd.nFileSizeHigh * (Int64(MAXDWORD) + 1)) + wfd.nFileSizeLow;
  windows.FindClose(fFile);
end;

constructor TExtendedStream.Create(OpenFromFilename:string);
begin
swapsize:=5242880;
ChangeSave:=nil;

if OpenFromFilename='' then
  begin
    aStream:=TMemoryStream.Create;
    inMemory:=True;
    Position:=0;
    Size:=0;
    protect:=False;
  end
else
  if fileexists(OpenFromFilename) then
    if GetFileSize(pChar(OpenFromFilename))<swapsize then
      begin
        aStream:=TMemoryStream.Create;
        TMemoryStream(aStream).LoadFromFile(OpenFromFilename);
        inMemory:=True;
        protect:=False;
        Position:=0;
        Size:=0;
      end
    else
      begin
        aStream:=TFilestream.Create(OpenFromFilename,fmOpenRead);
        inMemory:=False;
        protect:=true;
        Position:=0;
        Size:=astream.Size;
      end;
end;

function TExtendedStream.write(Const Buffer;Count:integer):integer;
var dummystream:TMemorystream;
    len:integer;
begin

  if inMemory=true then
  if sizeof(Buffer)+TMemorystream(aStream).size<swapsize then
  begin
    TMemorystream(aStream).Position:=self.Position;
    TMemorystream(aStream).Write(Buffer,count);
    size:=TMemorystream(aStream).Size;
    position:=TMemorystream(aStream).position;
  end
  else
    begin    //swapen
      dummystream:=TMemorystream(aStream);
      aStream:=TFilestream.Create(GetTempFileName('C:\'),fmcreate);
      dummystream.Position:=0;
      Tfilestream(aStream).CopyFrom(dummystream,dummystream.size);
      freeandnil(dummystream);
      inMemory:=False;
      protect:=false;
      Tfilestream(aStream).Position:=self.Position;
      Tfilestream(aStream).Write(Buffer,count);
      size:=Tfilestream(aStream).Size;
      position:=Tfilestream(aStream).position;
    end
  else //inMemory=false
    if not protect then
      begin
        TFileStream(aStream).position:=position;
        TFileStream(aStream).Write(Buffer,count);
        size:=Tfilestream(aStream).Size;
        position:=Tfilestream(aStream).position;
      end
    else
      begin //in Memory=false protect=true
        if ChangeSave=nil then
          begin
            ChangeSave:=TExtendedStream.create('');
            ChangeSave.Position:=0;
          end;
            ChangeSave.Position:=ChangeSave.Size;
            ChangeSave.write(self.Position,sizeof(self.Position));
            len:=sizeof(buffer);
            ChangeSave.write(len,sizeof(len));
            ChangeSave.write(Buffer,Count);
      end;
end;

function   TExtendedStream.read(var Buffer;Count:integer):integer;
var dummystream:TMemorystream;
    pos,len:integer;
    rel_start,rel_end:integer;
begin

  if inMemory=true then
  begin
    TMemorystream(aStream).Position:=self.Position;
    TMemorystream(aStream).read(Buffer,count);
    position:=TMemorystream(aStream).position;
  end
  else //inMemory=false
    if not protect then
      begin
        TFileStream(aStream).position:=position;
        TFileStream(aStream).Read(Buffer,count);
        position:=Tfilestream(aStream).position;
      end
    else
      begin //in Memory=false protect=true
        if ChangeSave<>nil then
          begin
            ChangeSave.Position:=0;
            ChangeSave.read(pos,sizeof(pos));
            ChangeSave.read(len,sizeof(len));
            rel_start:=position-pos;
            rel_end:=(position+count)-(pos+len);
            if rel_start>=0 then
              if rel_end>=0 then //readstream komplett in Changestream
                begin
                  ChangeSave.Position:=ChangeSave.Position+rel_start;
                  ChangeSave.read(Buffer,count);
                  ChangeSave.Position:=ChangeSave.Position+rel_end;
                end
              else
                begin //Readstream Ende liegt außerhalb von Changestream
                  ChangeSave.Position:=ChangeSave.Position+rel_start;
                  ChangeSave.read(Buffer,count+rel_end);
                  {hier hänge ich grade etwas}

                end;

          end;

      end;







end;



end.
Bin für alle Vorschläge dankbar.

Grüße Alleinherrscher

SirThornberry 19. Jul 2007 13:06

Re: Stream Ableitung, mit Eigenschaften von File- und Memstr
 
Die sinnvollste Variante ist es einen MemoryStream zu nehmen. Denn sobald die Größe nicht mehr in den normalen Ram passt lagert Windows sowieso in das SwapFile aus. Warum gerade diese Größe (5MB)?

[OT]
folgendes solltest du vermeiden und dir gar nicht erst angewöhnen
Delphi-Quellcode:
if inMemory=true then
[/OT]

[Edit]
Ich finde die Idee recht interessant einen "ReadOnly" Stream zu haben und nur die Änderungen gesondert zu speichern. Wenn du nichts dagegen hast würde ich die Idee gern versuchen umzusetzen.

alleinherrscher 19. Jul 2007 13:30

Re: Stream Ableitung, mit Eigenschaften von File- und Memstr
 
Ja, im moment Arbeitet mein Programm mit einem MemoryStream. Allerdings dauert das auslagern so ewig.

Beispiel: Ich lade manchmal relativ große Dateien in den Memorystream. Dabei macht ja windows dann nix anderes als Auslangern, also im Grunde "nochmal ne Kopie der Daten in der Auslangerungsdatei" anlegen.
Wenn ich jetzt aber die eigenschaften eines Filestreams hätte, müsste nix nochmal ausgelagert werden, alles ginge ganz fix und ich wäre glücklich. Problem nur: Ich muss aber leider Daten in den Stream schreiben, weswegen dadurch meine Originaldateien kaputt gehen würden.

Wichtig ist mir noch: Wenn ich jetzt nur die Änderungen speichere, müssten die sich auch von selbst in temporäre Dateien schreiben, falls sie Größer als die swapsize werden. Hm...ich finde es ist irgendwie relativ schwer zu beschreiben...

5mb hab ich einfach mal als Beispiel genommen, du kannst ja auch meinetwegen 50 mb nehmen....vollkommen egal... solange es halt noch in dem Ram passt...

Klar kannst du dich mal dran versuchen, wie gesagt, bin für jede Idee dankbar ;)

Robert Marquardt 19. Jul 2007 15:39

Re: Stream Ableitung, mit Eigenschaften von File- und Memstr
 
Nette Stream-Idee. Vielleicht mache ich eine Variante fuer die JCL. Da haben wir ein Sortiment abseitiger, aber nuetzlicher Streams.
Fuer diesen Stream ist es wichtig das er die Datei in der richtigen Directory anlegt und das im Konstruktor erledigt, damit ein Problem bei der Dateierstellung nicht erst spaeter auftritt.
Weiss jemand wie das bei Vista geregelt ist? Ist es sichergestellt das die Directory in der Environment-Variable TEMP auch fuer alle Benutzer schreibbar ist?

alleinherrscher 19. Jul 2007 15:58

Re: Stream Ableitung, mit Eigenschaften von File- und Memstr
 
Schätze mal, dass Vista %Temp% immer noch kennt.

Danke, Robert für das Lob ;) Mein Hauptproblem im Moment ist, dass ich nicht weiß wie ich "zwei Buffer" zusammenfasse: Beispiel:


http://lanfs.la.funpic.de/b1.jpg

TExtendetStream.Position:=110;
TExtendetStream.Read(Buffer,150);

Dann muss ich mir meinen Buffer aus dem Buffer vom Changestream und dem vom Originalstream zusammenbasteln...wie mache ich das am besten?

Robert Marquardt 19. Jul 2007 16:09

Re: Stream Ableitung, mit Eigenschaften von File- und Memstr
 
Das Problem ist nicht das Vista TEMP kennt, sondern ob die Directory sicher fuer alle Benutzer schreibbar ist. Ich habe schon viel von den MS-Programmierern erlebt und bin auf alles gefasst. Windows hatte nie ein so weitgehendes Konzept von Temporaerdateien wie Unix.
Bei deinem Pufferproblem habe ich gerade keine Lust dir zu helfen. Morgen vielleicht.

xaromz 19. Jul 2007 18:44

Re: Stream Ableitung, mit Eigenschaften von File- und Memstr
 
Hallo,

warum sollte das Temp-Verzeichnis für alle User beschreibbar sein? Jeder User hat doch sein eigenes Temp-Verzeichnis. Unter Vista ist das "C:\Users\<UserName>\AppData\Local\Temp", unter XP "C:\Dokumente und Einstellungen\<UserName>\Lokale Einstellungen\Temp".
Das Verzeichnis "C:\Windows\Temp" erlaubt aber immer noch allen Benutzern das Anlegen von Dateien.

Gruß
xaromz

Robert Marquardt 20. Jul 2007 05:46

Re: Stream Ableitung, mit Eigenschaften von File- und Memstr
 
Ich habe gerade gesehen das jemand gerade an JclBufferedStream arbeitet. Da duerfte diese Idee ziemlich genau dazupassen. Ich sag ihm mal bescheid.

alleinherrscher 20. Jul 2007 12:29

Re: Stream Ableitung, mit Eigenschaften von File- und Memstr
 
Hey, Robert! Dankeschön für deine Mithilfe!

Also wenn ich das User Account Control System von Vista richtig verstanden habe (habs nur überflogen) können Benutzer und Anwendungen in die zum Benutzerprofil gehörigen Ordner natürlich ohne Beschränkung schreiben und lesen, also auch in die entsprechenden Temp Folder. Für alle anderen Zugriffe auf Systemordner u.Ä. legt Windows für jeden User eine Art virtuelles Dateisystem an. Hier ein paar Infos dazu, die hoffentlich weiterhelfen:

http://www.microsoft.com/technet/tec...lt.aspx?loc=de

SirThornberry 20. Jul 2007 13:39

Re: Stream Ableitung, mit Eigenschaften von File- und Memstr
 
Zu Beitrag #5
Am einfachsten wäre es wenn man sich eine Liste macht wo die ganzen geänderten Buffer aufgeführt sind mit fester Größe. Wird etwas geschreiben suchst du also einfach ob der Bereich schon in der Liste der geänderten Teile ist. Wenn ja dann wird in dem teil gearbeitet. Wenn nicht wird der angelegt


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:43 Uhr.
Seite 1 von 2  1 2      

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