AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign TMemFileStream - Ein Zwitter aus TMemoryStream und TFileStream
Thema durchsuchen
Ansicht
Themen-Optionen

TMemFileStream - Ein Zwitter aus TMemoryStream und TFileStream

Ein Thema von Sir Rufo · begonnen am 1. Nov 2010 · letzter Beitrag vom 1. Nov 2010
Antwort Antwort
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#1

TMemFileStream - Ein Zwitter aus TMemoryStream und TFileStream

  Alt 1. Nov 2010, 16:16
Falls es mal jemand gebrauchen kann hier mein TMemFileStream
Delphi-Quellcode:
unit uMemFileStream;

{ **********************************************************************
  Version: 1.1 (2010-11-01)
  ----------------------------------------------------------------------
  TMemFileStream

  Dieser Stream verbindet die Vorteile von TMemoryStream und TFileStream
  Wenn der SystemCache ausreicht befindet sich der Stream komplett im
  RAM und auch nur dort. Erst wenn der SystemCache die Datenmenge nicht
  mehr speichern kann, wird der Stream physisch auf den Datenträger
  geschrieben.

  Der Vorteil bei der Verwendung, man braucht sich nicht mehr darum zu
  kümmern, ob das System genug RAM-Speicher für den Stream zur Verfügung
  hat. Die Grenze ist hierbei der freie Speicher auf dem Datenträger.

  Ein System mit ausreichend Hauptspeicher profitiert automatisch, weil
  der Stream auch direkt im Hauptspeicher verwaltet wird.

  Ein TMemoryStream ist allerdings deutlich performanter im Zugriff
  Ein TFileStream ist langsamer im Zugriff

  Hierbei handelt es sich um eine umgeschriebene TFileStream-Klasse

  ----------------------------------------------------------------------
  Historie:
  2010-11-01 Version 1.1
  + SetSize
  2010-11-01 Version 1.0

  ********************************************************************** }


interface

uses
  Classes;

type
  { TMemFileStream class }

  TMemFileStream = class( THandleStream )
  strict private
    FFileName : string;

  public
    procedure SetSize( const NewSize : Int64 ); override;
    procedure SaveToStream( const Stream : TStream );
    procedure SaveToFile( const FileName : string );
    procedure LoadFromStream( const Stream : TStream );
    procedure LoadFromFile( const FileName : string );
    constructor Create( const APath : string = '' );
    destructor Destroy; override;
  end;

implementation

uses
  Windows, SysUtils, RTLConsts;

const
  TEMP_FILE_PREFIX = 'mfs';

  // Ermittelt das TEMP-Verzeichnis

function GetDirTemp : string;
  var
    BufSize : Cardinal;
  begin
    SetLength( RESULT, MAX_PATH );
    BufSize := Windows.GetTempPath( Length( RESULT ), PChar( RESULT ) );
    SetLength( RESULT, BufSize );
    RESULT := ExcludeTrailingPathDelimiter( PChar( RESULT ) );
  end;

function GetTempFileName( const APath : string; const APrefix : string = TEMP_FILE_PREFIX ) : string;
  var
    NewTemp : array [ 0 .. MAX_PATH ] of Char;
    MPath : string;
  begin
    FillChar( NewTemp, SizeOf( NewTemp ), #0 );
    MPath := IncludeTrailingPathDelimiter( APath );
    Windows.GetTempFileName( PChar( MPath ), PChar( Copy( APrefix, 1, 3 ) ), 0, @NewTemp );
    RESULT := NewTemp;
  end;

function FileCreateTemp( const FileName : string; Mode : LongWord; Rights : Integer ) : Integer;
  const
    ShareMode : array [ 0 .. 4 ] of LongWord = ( 0, 0, FILE_SHARE_READ, FILE_SHARE_WRITE,
      FILE_SHARE_READ or FILE_SHARE_WRITE );
  begin
    RESULT := -1;
    if ( Mode and $F0 ) <= fmShareDenyNone then
      RESULT := Integer( CreateFile( PChar( FileName ),
          // Zugriff natürlich lesend und schreibend
          GENERIC_READ or GENERIC_WRITE,
          // wie auch immer
          ShareMode[ ( Mode and $F0 ) shr 4 ],
          // keine SecurityAttributes
          nil,
          // auf jeden Fall erzeugen, auch wenn der Dateiname schon existiert
          CREATE_ALWAYS,
          // Temporäre Datei
          // Daten werden nur dann physisch auf den Datenträger geschrieben,
          // wenn der Cache nicht mehr ausreicht
          FILE_ATTRIBUTE_TEMPORARY or
          // nicht indizieren
          // die Datei verschwindet ja eh wieder und würde somit nur Zeit kosten
            FILE_ATTRIBUTE_NOT_CONTENT_INDEXED or
          // verstecken
          // braucht darum auch niemand zu sehen
            FILE_ATTRIBUTE_HIDDEN or
          // am Ende automatisch löschen
          // und damit keinen Datei-Müll zurücklassen
          // Wir sind ja saubere Schweinchen
            FILE_FLAG_DELETE_ON_CLOSE,
          // keine Template benutzen
          0 ) );
  end;

{ TMemFileStream }

constructor TMemFileStream.Create( const APath : string );
  var
    Path : string;
    AFileName : string;
  begin
    if APath = 'then
      // Temp-Pfad holen
      Path := IncludeTrailingPathDelimiter( GetDirTemp )
    else
      Path := IncludeTrailingPathDelimiter( APath );

    // eindeutigen Dateinamen für eine temp. Datei holen
    AFileName := GetTempFileName( Path );

    // temp. Datei erzeugen
    inherited Create( FileCreateTemp( AFileName, fmShareExclusive, 0 ) );
    // gab es kein Handle, dann haben wir einen Fehler
    if FHandle = INVALID_HANDLE_VALUE then
      // tue Gutes und sprich davon :D
      raise EFCreateError.CreateResFmt( @SFCreateErrorEx, [ ExpandFileName( AFileName ),
        SysErrorMessage( GetLastError ) ] );

    FFileName := AFileName;
  end;

destructor TMemFileStream.Destroy;
  begin
    if FHandle <> INVALID_HANDLE_VALUE then
      FileClose( FHandle );
    inherited Destroy;
  end;

procedure SetSize( const NewSize : Int64 );
  begin
    inherited SetSize( NewSize );
  end;

procedure TMemFileStream.LoadFromFile( const FileName : string );
  var
    Stream : TFileStream;
  begin
    Stream := TFileStream.Create( FileName, fmOpenRead or fmShareDenyWrite );
    try
      LoadFromStream( Stream );
    finally
      Stream.Free;
    end;
  end;

procedure TMemFileStream.LoadFromStream( const Stream : TStream );
  begin
    Stream.Position := 0;
    SetSize( Stream.Size );
    Position := 0;
    CopyFrom( Stream, Stream.Size );
  end;

procedure TMemFileStream.SaveToFile( const FileName : string );
  var
    Stream : TFileStream;
  begin
    Stream := TFileStream.Create( FileName, fmCreate or fmShareExclusive );
    try
      SaveToStream( Stream );
    finally
      Stream.Free;
    end;
  end;

procedure TMemFileStream.SaveToStream( const Stream : TStream );
  var
    MPosition : Int64;
  begin
    MPosition := Position;
    Position := 0;
    Stream.CopyFrom( Self, Size );
    Position := MPosition;
  end;

end.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)

Geändert von Sir Rufo ( 1. Nov 2010 um 18:25 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.167 Beiträge
 
Delphi 12 Athens
 
#2

AW: TMemFileStream - Ein Zwitter aus TMemoryStream und TFileStream

  Alt 1. Nov 2010, 18:06
Auf SetSize reagierst du nicht, also da sollte ja die Dateigröße angepaßt werden.

Wieso schneidest du das Ende des übergebenen Pfades ab?
Es würde mir nicht gefallen, wenn ein anderer Pfade verwendet würde, als ich angegeben hab.
Delphi-Quellcode:
if APath = 'then
  // Temp-Pfad holen
  Path := GetDirTemp
else
  Path := IncludeTrailingPathDelimiter( APath );
Ansonsten sieht es gibt aus, vorallem FILE_ATTRIBUTE_TEMPORARY und FILE_FLAG_DELETE_ON_CLOSE.

Als kleinen Schönheitsfehler, das Const in const Stream : TStream ist unnötig
und im Prinzip auch "falsch", da du den Stream, also .Position kurzzeitig veränderst.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu ( 1. Nov 2010 um 18:11 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#3

AW: TMemFileStream - Ein Zwitter aus TMemoryStream und TFileStream

  Alt 1. Nov 2010, 18:23
Auf SetSize reagierst du nicht, also da sollte ja die Dateigröße angepaßt werden.
SetSize ist jetzt drin (hatte ich auch vermisst)
Wieso schneidest du das Ende des übergebenen Pfades ab?
Es würde mir nicht gefallen, wenn ein anderer Pfade verwendet würde, als ich angegeben hab.
Delphi-Quellcode:
if APath = 'then
  // Temp-Pfad holen
  Path := GetDirTemp
else
  Path := IncludeTrailingPathDelimiter( APath );
Ich hatte in einer vor-vor-version noch Aufrufe der Klasse mit einem Dateinamen und den wollte ich damit rausschneiden, also soweit ist dein Vorschlag da schon richtiger
Ansonsten sieht es gibt aus, vorallem FILE_ATTRIBUTE_TEMPORARY und FILE_FLAG_DELETE_ON_CLOSE.
merci
Als kleinen Schönheitsfehler, das Const in const Stream : TStream ist unnötig
und im Prinzip auch "falsch", da du den Stream, also .Position kurzzeitig veränderst.
öh, das const schützt doch nur davor, dass die übergebene Referenz nicht verändert wird. Die Properties erben ja nicht den const Status, oder
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.167 Beiträge
 
Delphi 12 Athens
 
#4

AW: TMemFileStream - Ein Zwitter aus TMemoryStream und TFileStream

  Alt 1. Nov 2010, 19:19
[edit]
Wegen dem SetSize ... hab grad gesehn, daß THandleStream das doch schon drin hat.
Hatte was im Kopf, daß dieses noch fehlt, aber das war nur beim TStream so, wo nur ein paar Dummymethoden vorhanden sind, welche eine Exception auslösen, wenn nicht mindestens eine der beiden SetSize-Methoden überschrieben wurden.
[/edit]

Jupp, CONST schützt nur vorm Ändern der Instanzvariable, bzw. vom Anlegen einer Kopie seitens Delphi.

Bei Klasseninstanzen gibt es keinen Unterschied, wenn man CONST verwendet oder nicht,
darum schreiben es viele auch nicht mit hin.

Nja, Const in einer Deklaration impliziert eine Nichtveränderung des Wertes, aber du Änderst schon den Inhalt des Objektes ... darum auch nur "Schönheitsfehler".


Mit und ohne CONST ist es formal korrekt (also im Bezug auf den Parameter), aber "logisch" kann man sich da gerne streiten.



Ich persönlich nutzt manchmal die Tatsache, daß hier mit und ohne CONST von Delphi gleich behandelt wird gerne mal aus.
> ohne CONST, quasi als implizites VAR, bei Veränderungen am Objekt
> mit CONST, wenn nix verändert wird
> und VAR, wenn die Instanzvariable verändert wird
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu ( 1. Nov 2010 um 19:26 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#5

AW: TMemFileStream - Ein Zwitter aus TMemoryStream und TFileStream

  Alt 1. Nov 2010, 20:31
Gibt es dafür ShareMode[ ( Mode and $F0 ) shr 4 ] keine Konstante? Und wenn nicht wäre es lesbarer, wenn man eine definieren würde, weil ich weiß aus dem Kopf nicht, was die Zeile macht.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.167 Beiträge
 
Delphi 12 Athens
 
#6

AW: TMemFileStream - Ein Zwitter aus TMemoryStream und TFileStream

  Alt 1. Nov 2010, 20:41
ShareMode ist die Konstande.
Der Mode-Parameter für TFileStream enthält kodiert 2 Werte.
> Zugriffsrechte wie GENERIC_READ und GENERIC_WRITE)
> Sharingrechte wie FILE_SHARE_READ und FILE_SHARE_WRITE

Das and/shr extrahiert nun den Anteil für die Sharingrechte (Mode and $F0).
Die Zugriffsrechte (Mode and $0F) werden hier nicht ausgewertet, da Eigene genommen werden.

Aber wenn man sich das richtig überlegt, dann braucht man dieses garnicht, da der Dateiname jedesmal dynamisch erstellt wird, wenn man einen TMemFileStream erstellt und es keinen sicheren Weg gibt, um an den Dateinamen eines TMemFileStream ranzukommen.

> Also entweder man speichert diesen Namen und bietet eventuell noch eine Möglichkeiten auch direkt auf einen bestehenden TMemFileStream, bzw. auf dessen Datei zuzugreifen (also einen weiteren TMemFileStream direkt auf eine bestehende Datei zu erstellen).

> Oder man verweigert lieber sämtliche Fremdzugriffe, indem man garkeine Sharingrechte angibt.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:02 Uhr.
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